spting mvc复习整理二

脑残

spring mvc 复习整理二(仗剑走天涯)

Spring Mvc 核心技术

设定字符集

1
2
3
4
5
6
7
8
9
10
11
12
13
<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>

返回JSON数据(序列化)

ajax请求后台获取数据,而不需要访问任何的页面,这种场景在前后分离的项目当中尤其重要

将我们的对象转化为json字符串。

将返回的内容直接写入响应体,不走视图解析器。

然后将Content-Type设置为application/json即可

fastjson

  • pom
1
2
3
4
5
6
<!--        fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
  • spring-mvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<mvc:annotation-driven >
<mvc:message-converters>
<bean id="fastjson" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
  • controller
1
2
3
4
5
6
7
8
9
10
11
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
@ResponseBody
public List<User> json1(){

ArrayList<User> users = new ArrayList<>() {{
add(new User("xiaobo", "xiaobo"));
add(new User("wangyibo", null));
}};

return users;
}

jackson

  • pom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
  • spring-mvc.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
<mvc:annotation-driven conversion-service="conversionService">

<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<!-- 自定义Jackson的objectMapper -->
<property name="objectMapper" ref="customObjectMapper" />
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>

</mvc:annotation-driven>
<!--注入我们写的对jackson的配置的bean-->
<bean name="customObjectMapper" class="com.dream.xiaobo.config.CustomObjectMapper"/>

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean id="stringToDateConverter" class="com.dream.xiaobo.config.DateConvertor"/>
</set>
</property>
</bean>
  • config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CustomObjectMapper extends ObjectMapper {

public CustomObjectMapper() {
super();
//去掉默认的时间戳格式
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为东八区
setTimeZone(TimeZone.getTimeZone("GMT+8"));
//设置日期转换yyyy-MM-dd HH:mm:ss
setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 设置输入:禁止把POJO中值为null的字段映射到json字符串中
configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
// 空值不序列化
setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 反序列化时,属性不存在的兼容处理
getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 序列化枚举是以toString()来输出,默认false,即默认以name()来输出
configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
}
}
  • controller
1
2
3
4
5
6
7
@PostMapping(value = "/insert")
public String user(@RequestBody UserVO user){

System.out.println(user);

return "user";
}

数据转换

配置文件方式

  • config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DateConvertor implements Converter<String, Date> {

@Override
public Date convert(String source) {

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

Date parse = null;

try {

parse = simpleDateFormat.parse(source);

} catch (ParseException e) {
e.printStackTrace();
}

return parse;
}
}
  • spring-mvc.xml
1
2
3
4
5
6
7
8
9
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean id="stringToDateConverter" class="com.dream.xiaobo.config.DateConvertor"/>
</set>
</property>
</bean>

<mvc:annotation-driven conversion-service="conversionService" />

注解方式

@DateTimeFormat:当从requestParam中获取string参数并需要转化为Date类型时,会根据此注解的参数pattern的格式进行转化 springmvc提供的

@JsonFormat:当从请求体中获取json字符序列,需要反序列化为对象时,时间类型会按照这个注解的属性内容进行处理 jackson提供的

1
2
3
4
5
6
@JsonFormat(
pattern = "yyyy-MM-dd",
timezone = "GMT-8"
)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;

大致处理过程

数据转换

数据检验

JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架

Constraint 详细信息
@Null 被注解的元素必须为 null
@NotNull 被注解的元素必须不为 null
@AssertTrue 被注解的元素必须为 true
@AssertFalse 被注解的元素必须为 false
@Min(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注解的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注解的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注解的元素必须是一个过去的日期
@Future 被注解的元素必须是一个将来的日期
@Pattern(value) 被注解的元素必须符合指定的正则表达式
@Email 被注解的元素必须是电子邮箱地址
@Length 被注解的字符串的大小必须在指定的范围内
@NotEmpty 被注解的字符串的必须非空
@Range 被注解的元素必须在合适的范围内

spring mvc 数据校验

  • pom
1
2
3
4
5
6
7
8
9
10
11
<!--        数据检验-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.9.Final</version>
</dependency>
  • data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {


@NotNull(message = "用户名不能为空")
private String userName;

@Pattern(regexp = "^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$", message = "手机号码不正确")
private String phone;

@Min(value = 1,message = "年龄不能小于{value}岁")
@Max(value = 120,message = "年龄不能大于{value}岁")
private Integer age;

@DateTimeFormat(pattern = "yyyy-MM-dd")
@Past(message = "必须是一个之前的时间")
private Date birthday;

@Email(message = "邮箱格式不正确")
private String email;
}
  • spring-mvc.xml
1
2
3
4
5
<bean id="localValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
</bean>
<!--注册注解驱动-->
<mvc:annotation-driven validator="localValidator"/>

视图解析器

默认视图解析器

1
2
3
4
5
6
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"  id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/page/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>

想要添加新的视图解析器可以删除之前的也可以添加

1
<property name="order" value="10"/>

order表示视图解析的 优先级 ,数字越小优先级越大(即:0为优先级最高,所以优先进行处理视图)

就是 order为0时,modelandview最先到达,然后返回到前端浏览器,然后才往order大的走

配置Thymeleaf视图解析器模板

  • spring-mvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--thymeleaf的视图解析器-->
<bean id="templateResolver"
class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="classpath:/thymeleafs/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML" />
<property name="cacheable" value="true" />
<!--这里要设置编码 -->
<property name="characterEncoding" value="UTF-8"/>
</bean>
<!--thymeleaf的模板引擎配置-->
<bean id="templateEngine"
class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<property name="enableSpringELCompiler" value="true" />
</bean>
<bean id="viewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine" ref="templateEngine"/>
</bean>
  • pom
1
2
3
4
5
6
7
8
9
10
11
12
<!--        thymeleaf模板-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.14.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring4 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.14.RELEASE</version>
</dependency>
  • 命名空间
1
<html xmlns:th="http://www.thymeleaf.org" >

全局异常捕获

HandlerExceptionResolver

  • 异常处理的两种形式

一种是当前方法捕获处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合

另一种是自己不处理,而是抛给调用者处理(throws),调用者再抛给它的调用者,也就是一直向上抛,指导传递给浏览器

所以我们可以用HandlerExceptionResolver统一进行处理

HandlerExcpetionRsoulver统一异常处理

service层尽量不要处理异常,如果自己捕获并处理了,异常就不生效了。特别是不要生吞异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
ModelAndView modelAndView = new ModelAndView();

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

if (ex instanceof ArithmeticException) {
return ArithmeticExceptionResolver();
}else{

return modelAndView;
}
}

public ModelAndView ArithmeticExceptionResolver() {

modelAndView.setViewName("exception");

modelAndView.addObject("exception", "系统维护中");
return modelAndView;
}
}
1
<bean class="com.dream.xiaobo.handler.GlobalExceptionResolver" />

@ControllerAdvice

该注解同样能实现异常的全局统一处理

@ControllerAdvice三个功能

  • 处理全局异常

  • 预设全局数据

  • 请求参数预处理

@ControllerAdvice 配合 @ExceptionHandler 实现全局异常处理

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
28
29
30
31
32
33
34
35
36
@ControllerAdvice
@Slf4j
public class GlobalExceptionResovlerController {

@ExceptionHandler(ArithmeticException.class)
public String processGrithmeticException(ArithmeticException exception, Model model){

model.addAttribute("exception","系统繁忙,请稍后重试");

log.error("发生了数学类的异常",exception);

return "exception";
}

@ExceptionHandler(BusinessException.class)
public String processBusinessException(BusinessException exception,Model model){

model.addAttribute("exception","系统繁忙,请稍后重试");


log.error("发生了业务类的异常",exception);

return "exception";
}

@ExceptionHandler(Exception.class)
public String processException(Exception exception,Model model){

model.addAttribute("exception","系统繁忙,请稍后重试");


log.error("发生了普通类的异常",exception);

return "exception";
}
}

资源处理

1
2
3
4
<!--    静态资源处理 放行-->
<mvc:resources mapping="/js/**" location="classpath:/static/js/"/>
<mvc:resources mapping="/css/**" location="classpath:/static/css/"/>
<mvc:resources mapping="/image/**" location="classpath:/static/image/"/>

拦截器

SpringMVC提供的拦截器类似于JavaWeb中的过滤器,只不过SpringMVC拦截器只拦截被前端控制器拦截的请求,而过滤器拦截从前端发送的【任意】请求

spring mvc拦截器常见的应用场景

登录认证拦截器

字符过滤器

日志操作拦截器

springmvc过滤器和拦截器

自定义拦截器

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
28
29
30
31
32
public class LoginInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

request.getSession().setAttribute("user","session");

Object user = request.getSession().getAttribute("user");

if (null == user) {
response.sendRedirect("/thymeleaf/login");
return false;
}else{
System.out.println("========preHandler");

// true放行 false不放行
return true;
}
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

System.out.println("========postHandler");

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=======afterCompletion");
}
}
  • spring-mvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<mvc:interceptors>
<mvc:interceptor>
<!--
mvc:mapping:拦截的路径
/**:是指所有文件夹及其子孙文件夹
/*:是指所有文件夹,但不包含子孙文件夹
/:Web项目的根目录
-->
<mvc:mapping path="/**"/>
<!--
mvc:exclude-mapping:不拦截的路径,不拦截登录路径
/toLogin:跳转到登录页面
/login:登录操作
-->
<mvc:exclude-mapping path="/thymeleaf/toLogin"/>
<mvc:exclude-mapping path="/thymeleaf/login"/>
<!--class属性就是我们自定义的拦截器-->
<bean id="loginInterceptor" class="com.dream.xiaobo.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

拦截器规则

preHandle:Controller方法处理请求前执行,根据拦截器定义的顺序,正向执行

postHandle:Controller方法处理请求后执行,根据拦截器定义的顺序,逆向执行。需要所有的preHandle方法都返回true时才会调用

afterCompletion:View视图渲染后处理方法:根据拦截器定义的顺序,逆向执行。preHandle返回true也会调用

spring mvc拦截器流程

拦截器流程图

Restful

restful是一种编程风格

利用@RequestMapping 指定要处理请求的URI模板和HTTP请求的动作类型

利用@PathVariable讲URI请求模板中的变量映射到处理方法参数上

利用Ajax,在客户端发出PUT、DELETE动作的请求

  • RestfulController
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@RestController
@RequestMapping(value = "/goods")
public class RestfulController {


@GetMapping(value = "/findAll")
public R findAll(){

List<Goods> goods = List.of(
new Goods("电脑", new BigDecimal("20000")),
new Goods("电话",new BigDecimal("4000"))
);

return R.success(goods);
}

@GetMapping(value = "/findAll/{id}")
public R findAllById(@PathVariable Integer id){
Goods goods = new Goods("电话", new BigDecimal("4000"));
return R.success(goods);
}

@PostMapping(value = "/save")
public R insert(@RequestBody Goods goods){
Goods goodss = new Goods(goods.getName(), goods.getPrice());
return R.success(goodss);
}

@PutMapping(value = "/update")
public R update(Goods goods){
Goods goods1 = new Goods(goods.getName(), goods.getPrice());
return R.success(goods1);
}

@DeleteMapping(value = "/delete/{id}")
public R deleteById(@PathVariable Integer id){

return R.error();
}

}
  • Goods
1
2
3
4
5
6
7
8
9
10
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {

private String name;

private BigDecimal price;

}
  • common
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
28
29
30
31
32
33
34
35
@Data
@Builder
public class R {

private static final Integer CODE_SUCCESS = 1000;

private static final Integer CODE_ERROR = 2000;

private static final String MESSAGE_SUCCESS = "操作成功";

private static final String MESSAGE_ERROR = "操作失败";

private String message;

private Integer code;

private Object data;

public static R success(){
return R.builder().code(CODE_SUCCESS)
.message(MESSAGE_SUCCESS).build();
}

public static R success(Object data){

return R.builder().code(CODE_SUCCESS)
.message(MESSAGE_SUCCESS).data(data).build();
}

public static R error(){
return R.builder().code(CODE_ERROR)
.message(MESSAGE_ERROR).build();
}

}
  • goods.html
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>商品</title>
</head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<h1>商品页面</h1>

<script>

// 为给定 ID 的 user 创建请求
axios.get('/goods/findAll')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

// 上面的请求也可以这样做
axios.get('/goods/findAll', {
params: {
id: 1
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

axios.post('/goods/save', {
name: '电脑',
price: 10000
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});






// $.ajax( {
// type : "GET",
// url : "http://localhost:8080/goods/findAll/1",
// dataType : "json",
// success : function(data) {
// console.log("get请求!---------------------")
// console.log(data)
// }
// });
//
// $.ajax( {
// type : "DELETE",
// url : "http://localhost:8080/goods/delete/1",
// dataType : "json",
// success : function(data) {
// console.log("delete请求!---------------------")
// console.log(data)
// }
// });
//
// $.ajax( {
// type : "put",
// url : "http://localhost:8080/goods/update",
// dataType : "json",
// data: {name:"电脑",price:123},
// success : function(data) {
// console.log("get请求!---------------------")
// console.log(data)
// }
// });
//
// $.ajax( {
// type : "post",
// url : "http://localhost:8080/goods/save",
// dataType : "json",
// data: {name:"电脑",price:123},
// success : function(data) {
// console.log("get请求!---------------------")
// console.log(data)
// }
// });


</script>
</body>
</html>
  • Controller
1
2
3
4
5
@RequestMapping(value = "/toGoods")
public String toGoods(){

return "goods";
}

你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:spting mvc复习整理二

文章作者:小博

发布时间:2022年05月23日 - 19:16

最后更新:2022年05月23日 - 19:17

原始链接:https://codexiaobo.github.io/posts/2829445748/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。