慢吞云雾缓吐愁 发表于 2024-12-18 18:40:34

Java框架 —— SpringMVC

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配置注册并初始化DisPatcherServletpublic class MyWebApplicationInitializer implements WebApplicationInitializer {

        @Override
        public void onStartup(ServletContext servletContext) {

                // Load Spring web application configuration
                AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
                context.register(AppConfig.class);

                // Create and register the DispatcherServlet
                DispatcherServlet servlet = new DispatcherServlet(context);
                ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
                registration.setLoadOnStartup(1);
                registration.addMapping("/app/*");
        }
}
[*]web.xml配置注册并初始化DisPatcherServlet<web-app>

        <listener>
                <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>

        <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/app-context.xml</param-value>
        </context-param>

        <servlet>
                <servlet-name>app</servlet-name>
                <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                <init-param>
                        <param-name>contextConfigLocation</param-name>
                        <param-value></param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>
        </servlet>

        <servlet-mapping>
                <servlet-name>app</servlet-name>
                <url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
运行原理

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


[*]控制器相干

[*]@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
@FunctionalInterface
public interface Converter<S, T> {
        /**
       * Convert the source object of type {@code S} to target type {@code T}.
       * @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
       * @return the converted object, which must be an instance of {@code T} (potentially {@code null})
       * @throws IllegalArgumentException if the source cannot be converted to the desired target type
       */
        @Nullable
        T convert(S source);
}实现

通过实现 Converter 接口


[*]自定义类型转换器 —— 实现Converter接口
 实体类
public class Goods {
    private String name;
    private double price;
    private int num;

    public Goods() {}
    public Goods(String name, double price, int num) {
      this.name = name;
      this.price = price;
      this.num = num;
    }

    @Override
    public String toString() {
      return "Goods{" +
                "name='" + name + '\'' +
                ", price=" + price +
                ", num=" + num +
                '}';
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public double getPrice() {
      return price;
    }

    public void setPrice(double price) {
      this.price = price;
    }

    public int getNum() {
      return num;
    }

    public void setNum(int num) {
      this.num = num;
    }
} Controller层
@Controller
@RequestMapping("/goods")
public class GoodsController {
    @RequestMapping("/show")
    public String add(@RequestParam("goods") Goods goods, Model model){
      model.addAttribute("goods",goods);
      return "showGoods";
    }
} 自定义类型转换 GoodsConverter
public class GoodsConverter implements Converter<String, Goods> {
    public GoodsConverter(){
      System.out.println("GoodsConverter...");
    }
    @Override
    public Goods convert(String source) {
      Goods goods = new Goods();
      if (source != null) {
            String[] split = source.split(",");
            if (split.length == 3) {
                goods.setName(split);
                goods.setPrice(Double.parseDouble(split));
                goods.setNum(Integer.parseInt(split));
                return goods;
            } else {
                throw new IllegalArgumentException(String.format(
                        "类型转换失败, 需要格式'apple, 10.58,200 ',但格式是[% s ] ", source));
            }
      }else {
            throw new IllegalArgumentException("source不能为空");
      }
    }
} spring-mvc.xml配置文件
<bean id="conversionService" >
    <property name="converters">
      <list>
            <bean />
      </list>
    </property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>通过@InitBinder注解(保举)

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

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


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


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

[*]preHandle():处理器执行前执行,假如返回false,则跳过处理器、拦截器postHandle()、视图渲染等,直接执行拦截器afterCompletion()
[*]postHandle():处理器执行后,视图渲染前执行,假如抛出非常,则跳过该方法直接执行afterCompletion()
[*]afterCompletion():视图渲染后执行,不管是否抛出非常
/**
* 定义一个拦截器
*/
public class HandlerInterceptor1 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      System.out.println("拦截器1的preHandle方法执行了...");
      //返回值true表示放行,false表示不放行
      return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      System.out.println("拦截器1的postHandle方法执 行了");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      System.out.println("拦截器1的afterCompletion方法执行了");
    }
}
[*]在SpringMVC配置文件中进行配置

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

 当我们在项目中配置了多个拦截器,他们的执行顺序由我们定义时的顺序决定,但是拦截器中的方法执行顺序不同
https://img2024.cnblogs.com/blog/3552536/202412/3552536-20241215140254957-1931954885.png
先顺序执行拦截器1、2、3的preHandle(),再逆序执行postHandle(),最后逆序执行afterCompletion()方法
拦截器和过滤器的区别


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








参考文章:

[*]SpringMVC入门学习(十二)----SpringMVC的拦截器
[*]Spring MVC 系列之拦截器 Interceptor 最全总结
[*]SpringMVC--Converter(类型转换器)详解

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