Java框架 —— SpringMVC

打印 上一主题 下一主题

主题 900|帖子 900|积分 2700

MVC 分层

MVC:Model View Controller(模型-视图-控制器)


  • 模型(Model):处理数据逻辑的部门;在web应用中,他通常包含与数据库交互的代码,负责数据的存储、检索和更新
  • 视图(View):将数据渲染为用户界面,视图只展示页面,不包含业务逻辑
  • 控制器(Controller):模型和视图之间的协调者,它接收用户的输入,调用视图和模型完成用户的请求
核心组件


  • 前端控制器(DisPatcherServlet):负责接收请求、分发,给予客户端响应
  • 处理器映射器(HandlerMapping):根据URL匹配查找能处理的Handler,并会将请求涉及到的拦截器和Handler一起封装
  • 处理器适配器(HandlerAdapter):根据HandlerMapping找到的Handler,适配执行对应的Handler
  • 请求处理器(Handler):处理现实请求的处理器(可明白为方法)
  • 视图解析器(ViewResolver):根据Handler返回的逻辑视图,解析并渲染成现实视图,并通报给DisPatcherServlet响应给客户端
DisPatcherServlet

SpringMVC围绕前端控制器模式计划,DisPatcherServlet必要Java配置或者XML配置根据Servlet规范进行声明和映射(一般使用XML配置)


  • Java配置注册并初始化DisPatcherServlet
    1. public class MyWebApplicationInitializer implements WebApplicationInitializer {
    2.         @Override
    3.         public void onStartup(ServletContext servletContext) {
    4.                 // Load Spring web application configuration
    5.                 AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    6.                 context.register(AppConfig.class);
    7.                 // Create and register the DispatcherServlet
    8.                 DispatcherServlet servlet = new DispatcherServlet(context);
    9.                 ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
    10.                 registration.setLoadOnStartup(1);
    11.                 registration.addMapping("/app/*");
    12.         }
    13. }
    复制代码
  • web.xml配置注册并初始化DisPatcherServlet
    1. <web-app>
    2.         <listener>
    3.                 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    4.         </listener>
    5.         <context-param>
    6.                 <param-name>contextConfigLocation</param-name>
    7.                 <param-value>/WEB-INF/app-context.xml</param-value>
    8.         </context-param>
    9.         <servlet>
    10.                 <servlet-name>app</servlet-name>
    11.                 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    12.                 <init-param>
    13.                         <param-name>contextConfigLocation</param-name>
    14.                         <param-value></param-value>
    15.                 </init-param>
    16.                 <load-on-startup>1</load-on-startup>
    17.         </servlet>
    18.         <servlet-mapping>
    19.                 <servlet-name>app</servlet-name>
    20.                 <url-pattern>/app/*</url-pattern>
    21.   </servlet-mapping>
    22. </web-app>
    复制代码
运行原理

 客户端发送请求到前端控制器DisPatcherServlet,前端控制器调用处理器映射器HandlerMapping查找请求对应的处理方法Handler,并将涉及到的拦截器和Handler一起封装返回给前端控制器,前端控制器再调用处理器适配器HandlerAdapter执行Handler,并将数据放入Model中或直接返回ModelAndView对象给前端控制器,前端控制器再调用视图解析器ViewResolver将逻辑视图解析为现实视图,并将模型数据通报给视图View,视图将其渲染成HTML,返回给前端控制器,前端控制器再将渲染好的视图返回给客户端

常用注解


  • 控制器相干

    • @Controller:类级别的注解,用于标志一个类为Controller的注解,负责接收用户请求,进行处理后,最终返回客户,一般结合@RequestMapping进利用用
    • @RestController:是@Controller和@ResponseBody的结合,它标志的类中,每个方法的返回值都会以 JSON 或 XML 的情势直接写入 HTTP 响应体中,相称于在每个方法上都添加了 @ResponseBody 注解

  • 请求映射相干

    • @RequestMapping:用于将请求映射到相应的处理方法上,可以作用于类或者方法级别
    • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping
      Restful 风格
      浏览器表单中只支持GET和POST请求,所以为了让浏览器实现PUT和DELETE,Spring提供了一个过滤器,将GET、POST请求转换成PUT、DELETE情势


  • 参数绑定相干

    • @RequestParam:将HTTP请求的参数绑定到控制器方法的参数上
    • @PathVariable:用于获取路径中的动态参数
    • @RequestBody:将请求体中的JSON或XML数据绑定到方法的参数对象上

  • 响应相干

    • @ResponseBody:将方法的返回值作为HTTP响应体的内容,常用于返回JSON或XML数据
    • @ResponseStatus:用于设置HTTP对应的状态码

自定义类型转换器

 页面通报的参数是String类型的,而在控制器中接收的参数是不固定的,对于基本数据类型,SpringMVC提供了类型转换器,对于不支持的目的类型,如:日期、自定义类型,则必要自定义类型转换器
顶层接口:Converter ——— 将类型 S 转换成 T
  1. @FunctionalInterface
  2. public interface Converter<S, T> {
  3.         /**
  4.          * Convert the source object of type {@code S} to target type {@code T}.
  5.          * @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
  6.          * @return the converted object, which must be an instance of {@code T} (potentially {@code null})
  7.          * @throws IllegalArgumentException if the source cannot be converted to the desired target type
  8.          */
  9.         @Nullable
  10.         T convert(S source);
  11. }
复制代码
实现

通过实现 Converter 接口


  • 自定义类型转换器 —— 实现Converter接口
    实体类
  1. public class Goods {
  2.     private String name;
  3.     private double price;
  4.     private int num;
  5.     public Goods() {}
  6.     public Goods(String name, double price, int num) {
  7.         this.name = name;
  8.         this.price = price;
  9.         this.num = num;
  10.     }
  11.     @Override
  12.     public String toString() {
  13.         return "Goods{" +
  14.                 "name='" + name + '\'' +
  15.                 ", price=" + price +
  16.                 ", num=" + num +
  17.                 '}';
  18.     }
  19.     public String getName() {
  20.         return name;
  21.     }
  22.     public void setName(String name) {
  23.         this.name = name;
  24.     }
  25.     public double getPrice() {
  26.         return price;
  27.     }
  28.     public void setPrice(double price) {
  29.         this.price = price;
  30.     }
  31.     public int getNum() {
  32.         return num;
  33.     }
  34.     public void setNum(int num) {
  35.         this.num = num;
  36.     }
  37. }
复制代码
Controller层
  1. @Controller
  2. @RequestMapping("/goods")
  3. public class GoodsController {
  4.     @RequestMapping("/show")
  5.     public String add(@RequestParam("goods") Goods goods, Model model){
  6.         model.addAttribute("goods",goods);
  7.         return "showGoods";
  8.     }
  9. }
复制代码
自定义类型转换 GoodsConverter
  1. public class GoodsConverter implements Converter<String, Goods> {
  2.     public GoodsConverter(){
  3.         System.out.println("GoodsConverter...");
  4.     }
  5.     @Override
  6.     public Goods convert(String source) {
  7.         Goods goods = new Goods();
  8.         if (source != null) {
  9.             String[] split = source.split(",");
  10.             if (split.length == 3) {
  11.                 goods.setName(split[0]);
  12.                 goods.setPrice(Double.parseDouble(split[1]));
  13.                 goods.setNum(Integer.parseInt(split[2]));
  14.                 return goods;
  15.             } else {
  16.                 throw new IllegalArgumentException(String.format(
  17.                         "类型转换失败, 需要格式'apple, 10.58,200 ',但格式是[% s ] ", source));
  18.             }
  19.         }else {
  20.             throw new IllegalArgumentException("source不能为空");
  21.         }
  22.     }
  23. }
复制代码
spring-mvc.xml配置文件
  1. <bean id="conversionService" >
  2.     <property name="converters">
  3.         <list>
  4.             <bean />
  5.         </list>
  6.     </property>
  7. </bean>
  8. <mvc:annotation-driven conversion-service="conversionService"/>
复制代码
通过@InitBinder注解(保举)

用于@Controller标注的类的方法上,表示为当前控制器注册一个属性编辑器,只对当前Controller有效,在其他方法执行前执行,做到预处理数据; @InitBinder标注的方法必须有WebDataBinder参数,用于表单到方法的绑定(属性编辑器可以明白为帮我们完成参数绑定的)
  1. @Controller
  2. public class UserController {
  3.     @InitBinder
  4.     public void initBinder(WebDataBinder binder){
  5.         binder.registerCustomEditor(LocalDate.class,new PropertyEditorSupport(){
  6.             @Override
  7.             public void setAsText(String text) throws IllegalArgumentException {
  8.                 //将请求参数转换为LocalDate类型
  9.                 setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
  10.             }
  11.         });
  12.     }
  13. }
复制代码
拦截器

拦截指定的用户请求,并进行相应的预处理和后处理,类似于Servlet中的过滤器,只不外比过滤器的功能更强大
应用场景


  • 日志记载:记载请求信息的日志,以便进行信息监控、信息统计等
  • 权限控制:如登录检测,进入处理器检测是否登录,没有登录返回登录页面
  • 性能监测:记载拦截器进入处理器和离开处理器的时间
配置及使用


  • 通过实现HandlerInterceptor接口来实现拦截器,接口中有三个方法preHandle()、postHandle()、afterCompletion()

    • preHandle():处理器执行前执行,假如返回false,则跳过处理器、拦截器postHandle()、视图渲染等,直接执行拦截器afterCompletion()
    • postHandle():处理器执行后,视图渲染前执行,假如抛出非常,则跳过该方法直接执行afterCompletion()
    • afterCompletion():视图渲染后执行,不管是否抛出非常
    1. /**
    2. * 定义一个拦截器
    3. */
    4. public class HandlerInterceptor1 implements HandlerInterceptor {
    5.     @Override
    6.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    7.         System.out.println("拦截器1的preHandle方法执行了...");
    8.         //返回值true表示放行,false表示不放行
    9.         return true;
    10.     }
    11.     @Override
    12.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    13.         System.out.println("拦截器1的postHandle方法执 行了");
    14.     }
    15.     @Override
    16.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    17.         System.out.println("拦截器1的afterCompletion方法执行了");
    18.     }
    19. }
    复制代码
  • 在SpringMVC配置文件中进行配置

    • 在使用标签对拦截器进行作用范围的设置。
    • 使用设置处理的请求,可以使用通配符,可以设置多个
    • 使用设置不必要拦截的请求,可以使用通配符,可以配置多个。但是使用的前提是必要先配置必要处理的请求范围,即必要先配置了才行,否则会有错误。
    1. <bean id="conversionService" >
    2.     <property name="converters">
    3.         <list>
    4.             <bean />
    5.         </list>
    6.     </property>
    7. </bean>
    8. <mvc:annotation-driven conversion-service="conversionService"/>
    复制代码
多个拦截器的执行顺序

 当我们在项目中配置了多个拦截器,他们的执行顺序由我们定义时的顺序决定,但是拦截器中的方法执行顺序不同

先顺序执行拦截器1、2、3的preHandle(),再逆序执行postHandle(),最后逆序执行afterCompletion()方法
拦截器和过滤器的区别


  • 拦截器不依赖于 Servlet 容器,过滤器依赖于 Servlet 容器
  • 拦截器是基于Java反射的,过滤器是基于函数回调
  • 拦截器只对action请求起作用,过滤器对几乎所以请求都有效
  • 拦截器可以访问action上下文、值栈中的对象,过滤器不能访问








参考文章:

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

慢吞云雾缓吐愁

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表