0%

SpringMVC2

属性copy方法

BeanUtils.copyProperties(被copy对象,目标对象);

@controller中的方法返回值

返回ModelAndView
方法结束之前,需要定义ModelAndView,将model和view分别进行设置。
1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping("findStudentsList")
public ModelAndView findStudentsList() throws Exception {

List<StudentCostom> studentsList = studentService.findStudentsList(null);
ModelAndView modelAndView = new ModelAndView();

modelAndView.addObject("studentsList", studentsList);
modelAndView.setViewName("index.jsp");

return modelAndView;

}
返回 stringe

​ 1、表示返回逻辑视图名。

​ 真正视图(isp路径)=前缀+逻辑视图名+后缀+

​ 2、redirect

​ return “redirect:findStudentsList”;

​ 3、forward

​ return “forward:findStudentsList”;

返回void

相当于普通的servlet,参数中添加request和response

@controller中的方法参数

一般的HttpServletRequest、HttpServletResponse、HttpSession

另外还有Model、ModelMap
model是一一个 接口,modelMap 是一个接口实现。
作用:将model数据填充到request域。

@RequestParam

​ 通过@RequestParam对简单类型的参数进行绑定。如果不使用,要求参数名必须和传入的参数(key/value)中的key相同,

​ 参数:required=true 指定该参数不能为null

​ defaultValue=””设置默认值,如果参数为null,则使用该默认值

1
2
3
4
5
@RequestMapping("findStudentsList")
public ModelAndView findStudentsList(HttpServletRequest request,@RequestParam("id") Integer sid) throws Exception {
String id = request.getParameter("id");
return modelAndView;
}

如果参数为自定义对象,那么前台传入的参数需要和对象中的属性名一致

自定义参数绑定
  • 对象

    1
    2
    3
    public class Person {
    private String address;
    private User user;
    1
    2
    3
    4
    5
    6
    7
    <!-- 页面 -->
    <form action="saveUserfz">
    <input type="text" name="user.uid"/><br>
    <input type="text" name="user.uname"/><br>
    <input type="text" name="address"/><br>
    <input type="submit" value="tijiao"/>
    </form>
    1
    2
    3
    4
    5
    @RequestMapping("saveUser")
    public String saveUser(Model model,Person p) {
    model.addAttribute("u", p);
    return "index";
    }
  • list

    1
    2
    3
    4
    5
    public class Person {
    private String address;
    private User user;
    private List<User> ulist;

    1
    2
    3
    4
    5
    6
    7
    8
    <form action="saveUserfzjh">
    <input type="text" name="address"/><br>
    用户一:<input type="text" name="ulist[0].uid"/><br>
    <input type="text" name="ulist[0].uname"/><br>
    用户二:<input type="text" name="ulist[1].uid"/><br>
    <input type="text" name="ulist[1].uname"/><br>
    <input type="submit" value="提交"/>
    </form>
    1
    2
    3
    4
    5
    @RequestMapping("saveUserfzjh")
    public String saveUserfzjh(Model model,Person p) {
    model.addAttribute("u", p);
    return "index";
    }
  • set

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class UserVo {

    private Set<User> userSet = new HashSet<>();

    public UserVo() {
    userSet.add(new User());
    userSet.add(new User());
    }

    public Set<User> getUserSet() {
    return userSet;
    }

    public void setUserSet(Set<User> userSet) {
    this.userSet = userSet;
    }
    }
    1
    2
    3
    4
    <form action="/echoSet" method="post">
      <input name="userList[0].name" value="张三" type="text"/>
      <input name="userList[0].age" value="21" type="text"/>
    </form>
    1
    2
    3
    4
    5
    6
    @RequestMapping(value = "/echoSet")
    @ResponseBody
    public String echoSet(UserVo userVo){
    Set<User> userSet = userVo.getUserSet();
    return JSON.toJSONString(userSet);
    }
  • map

    1
    2
    3
    4
    Public class QueryVo {
    private Map<String, Student> itemInfo = new HashMap<String, Student>();
    //get/set方法..
    }
    1
    2
    3
    4
    5
    6
    7
    <tr>
    <td>学生信息:</td>
    <td>
    姓名:<input type="text" name="itemInfo['name']"/>
    年龄:<input type="text" name="itemInfo['price']"/>
    </td>
    </tr>
自定义参数转换器
  • 新建一个类实现Converter接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CustomDateConverter implements Converter<String,Date>{
@Override
public Date convert(String source) {
//实现将日期串转成日期类型(格式是yyyy-MM-dd HH:mm:ss)
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
//转成直接返回
return simpleDateFormat.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e. printStackTrace();
}
//如果参数绑定失败返回null
return null;
}

在springmvc.xml中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
<mvc:annotation-driven
conversion-service="conversionService" />
<!-- 自定义参数绑定 -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<!-- 自定义类型转换器,可以定义无限个 -->
<bean class="com.syl.controler.converter.CustomDateConverter" />
</list>
</property>
</bean>

乱码解决

post乱码解决:

​ 在web.xml中添加过滤器

1
2
3
4
5
6
7
8
9
10
11
12
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

get乱码解决:

​ 修改tomcat配置文件添加编码与工程编码一致,如下:

1
2
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1"
redirectPort-"8443"/>

另外-种方法对参数进行重新编码:

1
2
String userName = 
new String(request.getParamter("userName").getBytes("lS08859-1"),"utf-8")

校验器

  • 导入jar包

    hibernate-validator-6.0.17.Final.jar

    hibernate-validator-annotation-processor-6.0.17.Final.jar

    hibernate-validator-cdi-6.0.17.Final.jar

  • springmvc.xml文件配置自定义校验器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <!-- 将校验器注入处理器适配器 -->
    <mvc:annotation-driven
    conversion-service="conversionService" validator="validator"/>

    <!--校验器-->
    <bean id= "validator"
    class= "org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!-- hibernate校验器 -->
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
    <!--指定校验使用的资源文件, 在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
    <property name="validationMessageSource" ref="messageSource" />
    </bean>
    校验错误信息配置文件-- >
    <bean id="messageSource”
    class="org.springframework.context.support.ReloadableResourceBundLeMessageSource">
    <property name="basenames">
    <list>
    <!--外部properties资源文件名-->
    <value>classpath:CustomValidationMessages</value>
    </list>
    </property>
    <!--资源文件编码格式-->
    <property name= "fileEncodings" value= "utf-8" />
    <!--对资源文件内容缓存时间,单位秒-->
    <property name= "cacheSeconds" value= "120">
    </bean>

CustomValidationMessages.properties

1
2
items.name.length.error=请输入1到30个字符的商品名称
items.createtime.isNUll=请输入商品的生产日期

entity中:

1
2
3
4
5
6
7
8
9
10
public class Items {
private Integer id;
//校验名称在1到30字符中间
//message是提示校验出错显示的信息
@Size(min=1, max=30 , message="{items.name.length.error}")
private String name;
//非空校验
@NotNull(message="{items.createtime.isNUll}")
private Date createtime;
...

在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
注意: @Validated和BindingResult bindingResult是配对出现,并且形参顺序是固定的(一前一后)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RequestMapping("updateStudent")
public String updateStudent(@Validated Student student, BindingResult bindingResult) throws Exception {

if (bindingResult.hasErrors()) {
// 输出错误信息
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
// 输出错误信息
System.out.println(objectError.getDefaultMessage());
}

}
return "";
}

定义多个校验分组(其实是一个java接口),分组中定义有哪些规则。每个controller方法使用不同的校验分组。

那就来两个接口

1
2
3
4
5
public interface ValidGroup1 {
//接口中不需要定义任何方法,仅是对不同的校验规则进行分组
}
public interface ValidGroup2 {
}

然后在实体类需要校验的属性上添加groups={ValidGroup1.class},将此校验方式分配到ValidGroup1组

1
2
3
//groups:此校验属于哪个分组,groups可以定义多个分组
@Size(min=1,max=30,message="{items.name.length.error}",groups={ValidGroup1.class})
private String name;

再然后在controller方法的参数中添加@Validated(value={ValidGroup1.class})指定校验规则为ValidGroup1组

1
public String updateStudent(@Validated(value={ValidGroup1.class}) Student student, BindingResult bindingResult) throws Exception {

数据回显

Student实体类对象数据传入controller中的方法之后,springmvc自动将其放入request作用域中,key为student(默认类名首字母小写)

怎么样自定义这个key呢

使用在Student student参数之前@ModelAttribute(“key”)就可以指定自己喜欢的key

1
public String updateStudent(@ModelAttribute("key") @Validated(value={ValidGroup1.class}) Student student, BindingResult bindingResult) throws Exception {

@ModelAttribute(“key”)还有一个作用就是写在某个方法上,作用是将这个方法的返回值放到request作用域中,并且指定key值为你自己写的key.

当然,还有最简单的一个方法就是直接使用Model来将这个对象加进request作用域中不用任何注解

1
2
3
4
5
public String updateStudent(Model model @Validated(value={ValidGroup1.class}) Student student, BindingResult bindingResult) throws Exception {

model.addAttribute("key",studnet);
return "";
}

!!注意:::@ModelAttribute(“key”)只能作用在包装对象上,不能用在基本数据类型上,基本数据类型只能用 model.addAttribute()来回显

全局异常处理器

首先自定义一个异常类CustomException.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CustomException extends Exception {
//异常信息
public String message;
public CustomException(String message){
super(message);
this. message = message;
}
public String getMessage() {
return message;
}

public void setMessage(String message) {
this . message = message;
}
}

再写一个全局异常处理器

思路:
系统遇到异常,需要在程序中手动抛出,dao 抛给service ,service 给controller, controller 抛给前端控制器,前端控制器调用全局异常处理器。

全局异常处理器处理思路:
解析出异常类型。
如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示
如果该异常类型不是系统自定义的异常,构造一个自定义的异常信息为“未知错误”并转发给error页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class CustomExceptionResolver implements HandlerExceptionResolver {

//handler是
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

CustomException customException = nul1;

if(ex instanceof CustomException){

customException = (CustomException)ex;

}else{
customException = new CustomException( "未知错误”) ;

}
//错误信息
String message = customException. getMessage();
ModelAndView modelAndView = new ModelAndView();
//将错误信息传到页面
modelAndView. addobject("message", message);
//指向错误页面
modelAndView. setViewName("error');
return modelAndView;
}
}

在springmvc.xml文件中配置这个全局异常处理器

1
2
<!--配置自定义全局异常处理器   只要实现HandlerExceptionResolver接口就是全局异常处理器  -->
<bean class="com.syl.exception.CustomExceptionResolver"></bean>

使用时直接

1
throw new CustomException("异常信息");

RESTful风格

1
2
3
4
5
6
7
///itemsView/{id}里边的{id}表示将这个位置的参数传到PathVariable指定名称中,并使用Integer id接收。
@RequestMapping("/itemsView/{id}")
public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id) throws Exception{
//调用service查询商品信息
ItemsCustom itemsCustom = itemsService.findItemsById(i d);
return itemsCustom;
}

在web.xml中配置restful的前端控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 前端控制器 -->
<servlet>
<servlet-name>springmvc_rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>springmvc_rest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

但是/这种配置url的方式会对静态资源的访问造成问题,这里需要在springmvc.xml文件里配置静态资源的解析方式

1
2
3
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/img/" mapping="/img/**"/>

context:component-scan mvc:annotation-driven的区别

<context:component-scan/> 只做扫描注解包下bean的工作,让bean生效。在这个基础上配置jsp的视图解析其实就可以正常访问jsp视图

如果没有<mvc:annotation-driven/>你就无法实现如接收返回json数据、参数验证、统一异常等功能。

赏口饭吃吧!