只是不愿随波逐流 ...|

lidongdongdong~

园龄:2年7个月粉丝:14关注:8

1、SpringMVC 总结

1、配置

1.1、web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--Spring 中提供的字符编码过滤器-->
<filter>
<filter-name>encFilter</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>encFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置 DispatcherServlet -->
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化参数: 指定 SpringMVC 配置文件的路径-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--启动立即初始化 Servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--配置 dispatcherServlet 的映射路径为 / 包含全部的 servlet, JSP 除外-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置 hiddenHttpMethodFilter, 将 POST 请求转换为 PUT 或者 DELETE 请求-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

1.2、spring-mvc.xml

// 自定义类型转换器
// 内置的日期类型转换器:2020/05/01(不⽀持 2020-05-01)
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
Date date = null;
try {
date = new SimpleDateFormat("yyyy-MM-dd").parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置 spring 包扫描-->
<context:component-scan base-package="com.zzw.controller" conversion-service="converter"/>
<!--类型转换器-->
<bean id="converter" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.zzw.converter.DateConverter"/>
</set>
</property>
</bean>
<!--处理器映射器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
<!--处理器适配器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
<!--开启 MVC 注解驱动, 自动配置: 处理器映射器和处理器适配器-->
<!--使用 <mvc:annotation-driven> 默认底层就会集成 jackson 进行对象或集合的 json 格式字符串的转换-->
<mvc:annotation-driven />
<!--视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--指定路径的前缀和后缀-->
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--静态资源释放方式一-->
<!--mapping:url, location:资源位置目录-->
<mvc:resources mapping="/static/**" location="/static/"/>
<!--
静态资源释放方式二
当前端控制器调用处理器映射器去查找资源不存在的时候, 先不要报错
而是选择将这个请求转交给程序外部容器(tomcat)的默认 servlet 处理(default)
-->
<mvc:default-servlet-handler/>
</beans>

1.3、文件上传

导入依赖

<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

在 spring-mvc.xml 中配置

<!--文件上传解析器, id 必须是固定的, 不能改, multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--单次上传文件大小, 单位 B(B -> KB -> MB), 10 MB = 10 * 1024 * 1024 B-->
<property name="maxUploadSize" value="10485760"/>
</bean>

2、执行流程

前端控制器 DispatcherServlet 三大组件

  • 处理器映射器:Handler Mapping
  • 处理器适配器:Handler Adapter
  • 视图解析器:View Resolver

image

  • 用户发送请求至前端控制器 DispatcherServlet
  • DispatcherServlet 收到请求,调用 HandlerMapping 处理器映射器
  • 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet
  • DispatcherServlet 调用 HandlerAdapter 处理器适配器
  • HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)
  • Controller 执行完成返回 ModelAndView
  • HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet
  • DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器
  • ViewReslover 解析后返回具体 View
  • DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中),DispatcherServlet 响应用户

3、请求控制

3.1、@RequestMapping

  • 控制请求方式(method)
    • @RequestMapping(value = "/***" , method = {RequestMethod.GET})
    • value / path = "URL"
    • method:Get、Post、Put、Delete
  • 控制请求参数(param)
    • param: 表示请求中必须包含名为 param 的参数
    • !param:表示请求中不能包含名为 param 的参数
    • param = value:表示请求中包含名为 param 的参数,但是值必须是 value
    • param != value:表示请求中包含名为 param 的参数,但是值不能是 value
    • {"param1", "param2 = value"}:可以将对于多个参数的要求写入数组
  • 请求头(headers)
@Controller
@RequestMapping("/zzw")
public class MyController {
// 定义一个处理请求的方法
// 返回值是 String, 用来表明要跳转页面的路径
// 这个字符串会到 spring-mvc.xml 中配置的视图解析器进行解析
@RequestMapping(path = {"/firstController.do"})
public String firstController() {
System.out.println("firstController");
return "first";
}
// 对请求方式进行控制
@RequestMapping(path = "/testRequest1.do", method = {RequestMethod.POST})
public String testRequest1() {
System.out.println("testRequest1");
return "first";
}
// 对请求参数进行控制
@RequestMapping(path = "/testRequest2.do", params = {"username != root", "password"})
public String testRequest2() {
System.out.println("testRequest2");
return "first";
}
// 对请求头进行控制
@RequestMapping(path = "/testRequest3.do", headers = {"Accept-Encoding = gzip, deflate"})
public String testRequest3() {
System.out.println("testRequest3");
return "first";
}
}

3.2、@PathVariable

@PathVariable 注解和 restful 风格的支持

@Controller
public class PathController {
@RequestMapping(path = "/testPathVariable/{id}/{username}")
public String testPathVariable(@PathVariable("id") String id, @PathVariable("username") String username) {
System.out.println("id:" + id);
System.out.println("username:" + username);
System.out.println("testPathVariable1");
return "first";
}
}

4、获取请求参数

4.1、普通类型 @RequestParam

@RequestParam:把请求中指定名称的参数给控制器中的形参赋值,名称参数不一致时可以使用它

  • value:请求参数中的名称
  • required:请求参数中是否必须提供此参数,默认为 true,表示必须提供,如果不提供将报错
  • defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
// HttpServletRequest 对象获取参数, 通过 SpringMVC 框架功能, 自动转换参数
// 处理单元参数列表中参数名必须和请求中的参数名一致
// 如不一致, 可以通过 @RequestParma 注解进行转换
@RequestMapping("/test")
public String test(String username, @RequestParam("pwd") String password) {
System.out.println("username:" + username);
System.out.println("password:" + password);
return "getParamSuccess";
}

http://localhost:8080/zzw/test?usErnaMe=&passwoRd=123&pagesize=5&students=张三&students=李四

// @RequestParam 注解一般标在请求参数的前面
// 作用 1: 用于指定当前参数是接收的前端传入的哪个参数的值
// 作用 2: 可以为请求参数设置默认值
// 作用 3: 当 @RequestParam 标注在一个参数之前时, 这个参数默认是必选要传值的, 但是可以使用 required = false 取消限制
// 作用 4: 可以使用他来标注接收一个 List 参数
@RequestMapping("/test")
public String test(@RequestParam("usErnaMe") String username, @RequestParam("passwoRd") String password,
@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(value = "sex", required = false) String sex,
@RequestParam("students") List<String> students) {
System.out.println(username + ":" + password);
System.out.println(pageNum + ":" + pageSize);
System.out.println(sex);
System.out.println(Arrays.toString(students.toArray()));
return "success";
}

4.2、数组类型

http://localhost:8080/zzw/test?strs=111&strs=222&strs=333

@RequestMapping("/test")
public void test(String[] strs) {
System.out.println(Arrays.asList(strs));
}

4.3、对象类型

  • 提交的参数名必须和 POJO 的属性名保持一致
  • springmvc 底层通过反射给参数列表的属性赋值
    通过 set 方法设置属性值的,不是直接通过操作属性
    POJO 的属性一定要有 set 方法,要不然就会接收失败
@RequestMapping("/test")
public void test(User user) {
System.out.println(user);
}

4.4、集合类型 @RequestBody

  • 要么 POJO 封装集合来完成
  • 要么 AJAX 异步完成:当使用 ajax 提交时,可以指定 contentType 为 json 形式
    那么在方法参数位置使用 @RequestBody 可以直接收集合数据而无需使用 POJO 进行包装

@RequestBody

  • required:是否必须有请求体,默认为 true
    当取值为 true 时,get 请求方式会报错
    如果取值为 false,get 请求得到是 null
  • 标注在参数前面,用于将请求体(get 没有请求体)中的 Json 数据转换成指定的对象
    如果没有具体的实体类来接收参数,就要用 Map 来接收
@RequestMapping("/test")
public void test(@RequestBody List<User> userList) throws IOException {
System.out.println(userList);
}
<script>
//模拟数据
var userList = new Array();
userList.push({username: "zhangsan",age: "20"});
userList.push({username: "lisi",age: "20"});
$.ajax({
type: "POST", // 请求方式必须是 POST, GET 不适用
url: "/zzw/test",
data: JSON.stringify(userList),
contentType : 'application/json;charset=utf-8'
});
</script>

4.5、@RequestHeader

用于获取请求消息头

  • value:提供消息头名称
  • required:是否必须有此消息头

@RequestHeader 注解可以获取请求头中的数据,并封装到指定的 map 中
@RequestHeader(headerKey) 指定的键接收请求头中某一项的值,例如 @RequestHeader("cookie") 就是接收请求头中的 cookie 的值

/*
* 接收请求头
* @RequestHeader 将请求头封装到指定的一个 map 结构中
* @RequestHeader(headerKey) 直接根据请求头中得键来获取值
*/
@RequestMapping("/test")
public String test(@RequestHeader Map<String, String> headers, @RequestHeader("cookie") String cookie) {
System.out.println(headers);
System.out.println(headers.get("cookie"));
System.out.println(cookie);
return "success";
}

4.6、@CookieValue

用于把指定 cookie 名称的值传入控制器方法参数

  • value:提供消息头名称
  • required:是否必须有此 cookie

4.7、@DateTimeFormat

日期类型转换 @DateTimeFormat(pattern = "yyyy-MM-dd") 可以用于:方法参数列表、类的属性

@RequestMapping("/test")
public string test(@DateTimeFormat(pattern "yyyy-MM-dd") Date birthday){
System.out.println(birthday);
return "success";
}
@Data
@ALLArgsconstructor
@NoArgsconstructor
public class Person implements Serializable {
private String name;
private String age;
private string gender;
private String[]hobby;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthdate;
}

5、响应

<!--视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
* 请求转发
- return "success"; 会去拼接配置文件中的前后缀
- return "forward:/error.jsp"; 写全路径
- request.getRequestDispatcher("/WEB-INF/success.jsp").forward(request, response); 写全路径
* 转发过程中传递数据:存入 request 域
- request.setAttribute("username", "zw");
- model.addAttribute("username", "zw");
- ModelAndView mv = new ModelAndView();
mv.setViewName("success"); 会去拼接配置文件中的前后缀
mv.addObject("username", "zw");
return mv;
* 响应重定向
- return "redirect:/error.jsp"; 写全路径
- response.sendRedirect(request.getContextPath() + "/error.jsp"); 写全路径

5.1、@ResponseBody

  • 方法的返回值不再作为界面跳转依据,将方法返回的数据自动转换为 JSON(使用 ObjectMapper)
  • 把我们要响应的数据直接 return 即可,返回值类型为要 return 的数据类型
  • 也可以这样回写数据:response.getWriter().print("hello world");

5.2、@RestController

@RestController = @Controller + @ResponseBody

  • 相当于 @Controller + @ResponseBody 两个注解的结合,返回 json 数据,不需要在方法前面加 @ResponseBody 注解了
  • 但使用 @RestController 这个注解,就不能返回 jsp、html 页面,视图解析器无法解析 jsp、html 页面

5.3、@JsonFormat

@JsonFormat 可以用于:方法参数列表、类的属性,响应 json 数据的处理

  • pattern:指定响应时间日期的格式
  • Timezone:指定响应的时区,否则会有 8 个小时的时间差
@DateTimeFormat(pattern = "yyyy-MM-dd") // 入参
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") // 出参
private Date birth;

6、异常处理

* 对于异常的处理一般有两种方式
- 当前方法处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合
- 当前方法不处理,出现异常后直接抛给调用者处理
* 使用 Spring 框架后,我们的代码最终是由框架来调用的
* 也就是说,异常最终会抛到框架中,然后由框架指定异常处理器来统一处理异常

image

6.1、配置方式

* SpringMVC 允许自定义一个全局异常处理类来统一处理异常
* 它要求这个类必须实现 HandlerExceptionResolver 接口,并重写类中异常的处理方法
@Component
public class GlobalExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o, Exception e) {
if (e instanceof ArithmeticException) {
System.out.println("数学异常");
} else if (e instanceof NullPointerException) {
System.out.println("空指针异常");
} else {
System.out.println("其它异常");
}
ModelAndView mv = new ModelAndView();
mv.setViewName("forward/error.jsp");
return mv;
}
}
<!--注解扫描-->
<context:component-scan base-package="com.zzw.handler"/>

6.2、注解方式

* SpringMVC 支持下面两个注解来实现全局异常处理
- @ControllerAdvice 要标注在类上,表示当前类是一个全局异常处理器的类
- @ExceptionHandler 标注在方法上,表示当前方法可以处理哪些异常
@ControllerAdvice // 表示当前这是一个全局异常处理器, 返回 Json 数据用 @RestControllerAdvice
public class GlobalExceptionHandlerAnno {
// 这个方法可以处理 Throwable 异常
@ExceptionHandler(Throwable.class)
public String handlerThrowable() {
System.out.println("大异常");
return "forward:/error.jsp";
}
// 这个方法可以处理 ArithmeticException 异常
@ExceptionHandler(ArithmeticException.class)
public String handlerArithmeticException() {
System.out.println("数学异常");
return "forward:/error.jsp";
}
// 这个方法可以处理 NullPointerException 异常
@ExceptionHandler(NullPointerException.class)
public String handlerNullPointerException() {
System.out.println("空指针异常");
return "forward:/error.jsp";
}
}

7、拦截器

7.1、什么是拦截器

拦截器是 Spring 提供的一种技术,它的功能似于过滤器 Filter,它会在进入 controller 之前,离开 controller 之后以及页面渲染完毕之后进行拦截
image

7.2、自定义拦截器

1、开发拦截器

要对拦截的资源做什么,自定义一个类实现 HandlerInterceptor 接口

public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("请求进入 controller 之前");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("请求离开 controller 之后");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("页面渲染完毕之后");
}
}

2、配置拦截器

在 spring-mvc.xml 中配置你要拦截哪些资源

<!--配置拦截器链-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截路径-->
<mvc:mapping path="/**"/>
<!--不拦截路径-->
<mvc:exclude-mapping path="/zzw/test"/>
<!--拦截器处理-->
<bean class="com.zzw.handler.MyHandlerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

7.3、自定义拦截器链

<!--配置拦截器链-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/zzw/test"/>
<bean class="com.zzw.handler.MyHandlerInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/zzw/test"/>
<bean class="com.zzw.handler.MyHandlerInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
// 结果
// 请求进入 controller1 之前
// 请求进入 controller2 之前
// 到达了后台 test
// 请求离开 controller2 之后
// 请求离开 controller1 之后
// 页面渲染完毕 2 之后
// 页面渲染完毕 1 之后

image

posted @   lidongdongdong~  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开