• Spring MVC


    当发送一个请求时,第一站是Spring的DispatcherServlet。与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器Servlet。前端控制器是常用的Web应用程序模式.Spring MVC中,DispatcherServlet就是前端控制器。DispatcherServlet的任务是将请求发送给Spring MVC控制器。控制器是一个用于处理请求的Spring组件。DispatcherServlet以会查询一个或多个处理器映射(handler mapping)来确定请求的下一站在哪里。处理器映射会根据请求所携带的URL信息来进行决策。一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器。到了控制器,请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示,这些信息被称为模型(model)。信息需要发送给一个视图(view),通常是JSP。控制器所做的最后一件事就是将模型数据打包,并且表示出用于渲染输出的视图名。它接下来会将请求连同模型和视图名发送回DispatcherServlet。这样,控制器就不会与特定的视图相耦合,传递个DispatcherServlet的视图名并不直接表示某个特定的JSP/html。它仅仅传递一个逻辑名称,这个名称将会用来查找产生结果的真正试图。DispatcherServlet将会使用试图解析器(view resolver)来将逻辑试图名匹配为一个特定的试图实现。最后一站是试图的实现。在这里DispatcherServlet交付模型数据。试图将使用模型数据渲染输出,这个输出会通过响应对象传递给客户端。

    配置DispatcherServlet

      Spring提供了AbstractAnnotationConfigDispatcherServletInitializer的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,也就是AbstractAnnotationConfigDispatherServletInitializer。

    AbstractAnnotationConfigDispatherServletInitializer有三个方法:

    getServletMappings():将一个或多个路径映射到DispatcherServlet上

    getServletConfigClasses():要求DispatcherServlet加载应用上下文

      当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean。

    getRootConfigClasses():返回配置ContextLoaderListener创建的应用上下文中的bean

      ContextLoaderListener会加载包含Web组件的bean,如控制器,视图解析器以及处理器映射import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

    public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class<?>[] {RootConfig.class};
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class<?>[] {WebConfig.class};
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[] {"/"};
        }

    @Override
    protected Filter[] getServletFilters()[
    return new Filter[]{new MyFilter[]};
    } }

    通过调用DefaultServletHanlderConfigurer的enable()方法,要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本来来处理此类请求。

    Spittr应用有两个基本的领域概念:Spitter(应用的用户)和Spittle(用户发布的简短状态更新)。

    SpringMVC允许以多种方式将客户端中国的数据传送到控制器的处理器方法中,包括:查询参数(Query Parameter),表单参数(Form Parameter)和路径变量(Path Variable)。

    Spring支持Java校验API(Java Valildation API,又称JSR-303)。在Spring MVC中要使用Java校验API的话,并不需要什么额外的配置。只要保证在类路径下包含这个Java API的实现即可。

    Java校验API定义了多个注解

    @AssertFalse  所注解的元素必须是Boolean类型,且值为false

    @AssertTrue   所注解的元素必须是Boolean类型,且值为true

    @DecimalMax   所注解的元素必须是数字,并且它的值要小于或等于给定的BigDecimalString值

    @DecimalMin  所注解的元素必须是数字,并且它的值要大于或等于给定的BigDecimalString值

    @Digits       所注解的元素必须是数字,并且它的值必须有指定的位数

    @Future         所注解的元素的值必须是一个将来的日期    

    @Max       所注解的元素必须是数字,并且他的值要小于或等于给定的值

    @Min        所注解的元素必须是数字,并且它的值要大于或等于给定的值

    @NotNull    所注解元素的值必须不能为null

    @Null       所注解元素的值必须为null

    @Past      所注解的元素的值必须是一个已过去的日期

    @Pattern           所注解的元素的值必须匹配给定的正则表达式

    @Size        所注解的元素的值必须是String,集合或数组,并且它的长度要符合给定的范围

    AbstractAnnotationConfigDispatcherServletInitializer可以做一些额外的配置

      在AbstractAnnotationConfigDispatcherServletInitilizer将DispatcherServlet注册到Servlet容器后,会调用customizeRegistration(),并将Servlet注册后得到的Registration.Dynamic传递进来,通过重载customizeRegistration()方法,可以对DispatcherServlet进行额外的配置。

    @Override
    protected void customizeRegistration(Dynamic registration){
        registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
    }

      AbstractAnnotationConfigDispatcherServletInitializer会创建DispathcerServlet和ContextLoaderListener。当我们想向Web容器中注册其他组件时,只需要创建一个新的初始化容器就可以了,最简单的方式就是实现Spring的WebApplicationInitializer接口。

    public class MyServletInitializer implements WebApplicationInitializer{
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class);
            Dynamic filter = servletContext.addFilter("myFilter", MyFilter.class);   
            myServlet.addMapping("/custom/**");
    filter.addMappingForUrlPatterns(null, false, "/custom/**"); } }

    在web.xml中搭建Spring MVC

    <?xml version="1.0" encoding="UTF-8" ?>
    <web-app version="2.5"
        xmlns="http://java.sun.com/xml/nx/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
      <display-name>Archetype Created Web Application</display-name>
      
      <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
      </context-param>
    
      <context-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>/WEB-INF/spring/root-context.xml</param-value>  
      </context-param>    
    
      <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
    
      <servlet>
         <servlet-name>appServlet</servlet-name>
         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    
          <load-on-startup>1</load-on-startup>
      </servlet>    
    
      <servlet-mapping>
         <servlet-name>appServlet</servlet-name>
         <url-pattern>/<url-pattern>
      </servlet-mapping>
    
    </web-app>

    contextLoaderListener和DispatcherServlet会各自加载一个Spring应用上下文。上下文参数contextConfigLocation指定了一个XML文件(root-context.xml),它会被ContextLoaderListener加载。

    DispatcherServlet会根据Servlet的名字找到一个文件,并基于该文件加载应用上下文。Servlet的名字是appServlet,因为DispatcherServlet会从“/WEB-INF/appServlet.xml”文件中加载器应用上下文。也可在Servlet上指定一个contextConfigLocation初始化参数。

      <servlet>
         <servlet-name>appServlet</servlet-name>
         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    
          <init-param>
             <param-name>contextConfigLocation</param-name>
             <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
      </servlet>    

    设置web.xml使用基于Java的配置

    <?xml version="1.0" encoding="UTF-8" ?>
    <web-app version="2.5"
        xmlns="http://java.sun.com/xml/nx/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
      <display-name>Archetype Created Web Application</display-name>
      
      <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
      </context-param>
      
      <context-param>
          <param-name>contextClass</param-name>
          <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
      </context-param>
      
      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>cherry.config.RootConfig</param-value>
      </context-param>
      
      <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      
      <servlet>
          <servlet-name>appServlet</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          <init-param>
              <param-name>contextClass</param-name>
              <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
          </init-param>
          <init-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>cherry.config.WebConfig</param-value>
              <load-on-startup>1</load-on-startup>
          </init-param>
      </servlet>
      
      <servlet-mapping>
          <servlet-name>appServlet</servlet-name>
          <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>

    DispatcherServlet并没有实现任何解析multipart请求数据的功能。它将该任务委托给了Spring中MultipartResolver策略接口的实现,通过这个实现类来解析multipart请求中的内容。从Spring3.1开始,Spring内置了两个MultipartResolver的实现供我们选择:

      CommonsMultipartResolver:使用Jakarta Commons FileUpload解析multipart请求

      StandardServletMultipartResolver:依赖于Servlet3.0对multipart请求的支持

    使用Servlet3.0解析multipart请求

      1.在Spring应用上下文中声明bean

    @Bean
    public MultipartResolver multipartResolver() throws IOException(){
        return new StandardServletMultipartResolver();
    }

      2.在AnnotationConfigDispatcherServletInitializer或AbstractDispatcherServletInitializer中重载customizeRegistration()方法来配置multipart具体细节--临时路径,上传文件最大容量,整个multipart请求最大容量,如果文件达到了一个指定最大容量,将会写入到临时路径中

    @Override
    protected void customizeRegistration(Dynamic regsitration){
        registration.setMultipartConfig(new MultipartConfigElement("tmp/spittr/uploads", 2097152, 4194304, 0));
    }

      3.使用web.xml配置MultipartConfigElement

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <multipart-config>
            <location>/tmp/spittr/uploads</location>
            <max-file-size>2097152</max-file-size>
            <max-request-size>4194304</max-request-size>
        </multipart-config>
    </servlet>

    配置Jakarta Commons FileUpload multipart解析器

      在Spring应用上下文中声明bean并对其进行配置

    @Bean
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setUploadTempDir("tmp/spittr/uploads");
    multipartResolver.setMaxUploadSize(2097152);
    multipartResolver.setMaxInMemorySize(0);
    retrun multipartResolver;

    }

    处理异常

      Servlet请求的输出是一个Servlet相应,在处理异常时,输出仍是Servlet响应,一场必须要以某种方式转换为响应。

    Spring提供了多种方式将异常转换为响应:

      特定的Spring异常将会自动映射为指定的HTTP状态码

      异常上可以添加@ResponseStatus注解,从而将其映射为某一个HTTP状态码

      在方法上可以添加@ExceptionHandler注解,使其用来处理异常

    异常处理的最简单方式是将其映射到HTTP状态码上,进而放到响应之中。

    Spring会将自身的一些异常自动转换为合适的状态码

    BindException                400 - Bad Request

    HttpMessageNotReadbleException      400 - Bad Request

    MethodArgumentNotValidException        400 - Bad Request

    MissingServletRequestParameterException   400 - Bad Request

    MissingServletRequestPartException      400 - Bad Request

    TypeMismatcheException           400 - Bad Request

    NoSuchRequestHandlingMethodException  404 - Not Found

    HttpRequestMethodNotSupportedException 405 - Method Not Allowed

    HttpMediaTypeNotAcceptableException         406 - Not Acceptable

    HttpMediaTypeNotSupportedException    415 - Unsupported Media Type

    ConversionNotSupportedException              500 - Internal Server Error

    HttpMessageNotWritableException              500 - Internal Server Error

    DispatcherServlet处理过程中或执行检验时出现问题时,Spring会抛出异常。如果DispatcherServlet无法找到合适处理请求的控制器方法,将会抛出NoSuchRequestHandlingMethodException异常,产生404状态码的响应

    @ResponseStatus:将异常映射为特定的状态码

    @ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
    public class SpittleNotFoundException extends RuntimeException{}

    @ExceptionHandler会处理同意控制器中所有处理器方法所抛出的异常

    @ExceptionHandler
    public String handleSpittleNotFoundException(){
        return "error/spittleNotFound";
    }

    控制器通知(controller advice)是任意带有@ControllerAdvice注解的类。这个类会包含一个或多个如下类型的方法:

      @ExceptionHandler注解标注的方法;

      @InitBinder注解标注的方法;

      @ModelAttribute注解标注的方法;

    在带有ControllerAdvice注解的类中,上述方法会运用都整个应用程序素有控制器中带有@RequestMapping注解的方法上

    @ControllerAdvice
    public class AppWebExceptionHandler {
    
        @ExceptionHandler(DuplicateSpittleException.class)
        public String handleDuplicationSpittle(){
            return "error/duplicate";
        }
        
    }

    重定向

      在处理完POST请求后,执行重定向可以防止用户点击浏览器的刷新按钮或后腿箭头时,客户端重新执行危险的POST请求。当控制器方法返回的String值以"redirect:"开头时,这个String不是用来查找视图的,而是用来知道浏览器进行重定向的路径。

      当一个处理器方法完成之后,该方法所指定的模型数据将会复制到请求中,并作为请求中的属性,请求会转发(forward)到视图上进行渲染。因为控制器方法和视图所处理的是同一个请求,所有在转发的过程中,请求属性能够得以保存。

      对于发起重定向的方法处理数据有两种方式:

        使用URL模板以路径和/或查询参数的形式传递数据

        通过flash属性发送数据

    通过URL模板进行重定向

      使用String直接连接是很危险的,如 return "redirect:/spitter/{username}";

      Spring提供了使用模板的方法来定义重定向URL。

      username作为占位符填充到了URL模板中,而不是直接连接到重定向String中。firstName属性没有匹配重定向URL中的任何占位符,所以它会自动以查询参数的形式附加到重定向URL上。所以下面URL的路径是"/spitter/username?firstName=firstName"

    @RequestMapping(value = "register", method = RequestMethod.POST)
    public String processRegistration(Spitter spitter, Model model){
        spitterRepository.save(spitter);
        model.addAttribute("username", spitter.getUsername);
        model.addAttribute("firstName", spitter.getFirstName);
        return "redirect:/spitter/{username}";
    }

    使用flash

      Spring提供了将数据发送为flash属性的功能。flash属性会一直携带这些数据知道下一次请求,然后会消失。在重定向执行之前,所有的flash属性都会复制到会话中。在重定向后,存在会话中的flash属性会被取出,并从会话转移到模型之中。

    @RequestMapping(value = "register", method = RequestMethod.POST)
    public String processRegistration(Spitter spitter, RedirectAttributes model){
        spitterRepository.save(spitter);
        model.addAttribute("username", spitter.getUsername());
        model.addFlashAttribute("spitter", spitter);
        return "redirect:/spitter/{username}";
    }
    
    @RequestMapping(value = "/{username}" , method = RequestMethod.GET)
    public String showSpitterProfile(@PathVariable String username. Model model){
        if(!model.containsAttribute("spitter")){
            model.addAttribure(new Spitter());
        }
        return "profile";
    }
  • 相关阅读:
    read()系统调用的流程(转个贴)
    linux kernel reading
    开博第一篇
    让人崩溃的Visual C++ 2005 SP1 Redistributable Package (x86),为啥我下不下来?
    System Call on Linux 2.6 for i386(2) int 0x80与systementer
    http://www.netyi.net/in.asp?id=yuanxianping
    取Insert产生的ID
    递归触发器资料
    Commit Trans和Rollback Trans在有触发器操作时的区别
    转:安全配置SQL Server2000服务器
  • 原文地址:https://www.cnblogs.com/forerver-elf/p/6383530.html
Copyright © 2020-2023  润新知