• springboot学习章节代码-Spring MVC基础


    1、项目搭建。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.zhen</groupId>
        <artifactId>highlight_springmvc4</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <properties>
            <!-- Generic Properties -->
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    
            <!-- Web -->
            <jsp.version>2.2</jsp.version>
            <jstl.version>1.2</jstl.version>
            <servlet.version>3.1.0</servlet.version>
    
            <!-- Spring -->
            <spring-framework.version>4.1.5.RELEASE</spring-framework.version>
    
            <!-- Logging -->
            <logback.version>1.0.13</logback.version>
            <slf4j.version>1.7.5</slf4j.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-web-api</artifactId>
                <version>7.0</version>
                <scope>provided</scope>
            </dependency>
    
            <!-- Spring MVC -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring-framework.version}</version>
            </dependency>
    
            <!-- 其他web依赖 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>${jstl.version}</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>${servlet.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>${jsp.version}</version>
                <scope>provided</scope>
            </dependency>
    
            <!-- Spring and Transaction -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>${spring-framework.version}</version>
            </dependency>
    
            <!-- 使用SLF4J和LogBack作为日志 -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/log4j/log4j -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.16</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>${logback.version}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>${logback.version}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
                <version>${logback.version}</version>
            </dependency>
    
            <!-- jackson以及先关依赖,对象与json和xml的互换 -->
            <dependency>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
                <version>2.5.3</version>
            </dependency>
    
            <!-- file upload -->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
            </dependency>
            <!-- 非必须,简化io操作 -->
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.3</version>
            </dependency>
    
            <!-- 测试依赖 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring-framework.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.3</version>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
                <!-- 内置jetty插件 -->
                <plugin>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-maven-plugin</artifactId>
                    <version>9.4.3.v20170317</version>
                    <configuration>
                        <httpConnector>
                            <port>8080</port>
                        </httpConnector>
                        <webAppConfig>
                            <contextPath>/highlight_springmvc4</contextPath>
                        </webAppConfig>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    
    </project>
    pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="1 seconds">
        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
            <resetJUI>true</resetJUI>
        </contextListener>
    
        <jmxConfigurator/>
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>logback: %d{HH:mm:ss.SSS} %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        <logger name="org.springframework.web" level="DEBUG">
            <root level="info">
                <appender-ref ref="console"/>
            </root>
        </logger>
    </configuration>
    logback.xml

    页面放在src/main/resources下,是为了习惯spring Boot的页面放置方式

    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 9:35
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Insert title here</title>
    </head>
    <body>
        <pre>
            Welcome to Spring MVC world
        </pre>
    </body>
    </html>
    index.jsp

    springMvc配置:(有些配置不需要可以不放置)

    package com.zhen.highlight_springmvc4;
    
    import com.zhen.highlight_springmvc4.interceptor.DemoInterceptor;
    import com.zhen.highlight_springmvc4.messageconverter.MyMessageConverter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.web.multipart.MultipartResolver;
    import org.springframework.web.multipart.commons.CommonsMultipartResolver;
    import org.springframework.web.servlet.config.annotation.*;
    import org.springframework.web.servlet.view.InternalResourceViewResolver;
    import org.springframework.web.servlet.view.JstlView;
    
    import java.util.List;
    
    /**
     * @author zhen
     * @Date 2018/7/3 9:37
     */
    @Configuration
    @EnableWebMvc
    @EnableScheduling
    @ComponentScan("com.zhen.highlight_springmvc4")
    public class MyMvcConfig extends WebMvcConfigurerAdapter {
    
        @Bean
        public InternalResourceViewResolver viewResolver(){
            InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
            viewResolver.setPrefix("/WEB-INF/classes/views/");
            viewResolver.setSuffix(".jsp");
            viewResolver.setViewClass(JstlView.class);
            return viewResolver;
        }
    
        @Bean
        public MultipartResolver multipartResolver(){
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
            multipartResolver.setMaxUploadSize(1000000);
            return multipartResolver;
        }
    
        @Bean
        public MyMessageConverter converter(){
            return new MyMessageConverter();
        }
    
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters){
            converters.add(converter());
        }
    
    
    
        @Bean
        public DemoInterceptor demoInterceptor(){
            return new DemoInterceptor();
        }
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(demoInterceptor());
        }
    
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/index").setViewName("/index");
            registry.addViewController("/toUpload").setViewName("/upload");
            registry.addViewController("/converter").setViewName("/converter");
            registry.addViewController("/sse").setViewName("/sse");
            registry.addViewController("/async").setViewName("/async");
        }
    
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            configurer.setUseSuffixPatternMatch(false);
        }
    
    
    }
    MyMvcCOnfig

      Demo搭建中只配置视图解析器用来映射路径和实际页面的位置。

      @EnableWebMvc注解会开启一些默认配置

    web配置:

    package com.zhen.highlight_springmvc4;
    
    import org.springframework.web.WebApplicationInitializer;
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.servlet.DispatcherServlet;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:00
     */
    public class WebInitializer implements WebApplicationInitializer {//WebApplicationInitializer是Spring用来配置Servlet3.0+配置的接口
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            context.register(MyMvcConfig.class);
            context.setServletContext(servletContext);//注册配置类
    
            ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));//注册Spring MVC的DispatcherServlet
            servlet.addMapping("/");
            servlet.setLoadOnStartup(1);
            servlet.setAsyncSupported(true);//开启异步方法支持
        }
    }
    WebInitializer

    简单控制器:

    package com.zhen.highlight_springmvc4;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:04
     */
    @Controller //利用@Controller注解声明是一个控制器
    public class HelloController {
    
        @RequestMapping("/index") //@RequestMapping配置URL和方法之间的映射
        public String hello(){
            return "index"; //通过ViewResolver的Bean配置,返回值为index,说明页面放置的路径为/WEB-INF/classes/views/index.jsp
        }
    }
    HelloController

    2、Spring MVC的常用注解

    @Controller表明这个类是Spring MVC的Controller,dispatcher servlet会自动扫描注解了此注解的类,并将web请求映射到注解了@RequestMapping的方法上。在声明普通Bean的时候,使用@Component、@Service、@Repository、@Controller是等同的,因为它们都组合了@Compoment。独特的功能使用独特的注解。

    @RequestMapping用来映射web请求、处理类和方法。可注解在类上和方法上,注解在方法上的@RequestMapping路径会继承注解在类上的路径。支持对request和response的媒体类型进行配置

    @ResponseBody支持将返回值放在response体内,而不是一个页面,ajax可使用

    @RequestBody允许将request的参数在request体重,而不是直接连接在地址后面

    @PathVariable用来接收路径参数,此注解放在在参数前面

    @RestController是个组合注解组合了@Controller和@ResponseBody两个注解

    例子:

    添加jackson以及相关依赖,获得对象和json或xml之间转换:
    
     <!-- jackson以及先关依赖,对象与json和xml的互换 -->
            <dependency>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
                <version>2.5.3</version>
            </dependency>
    
    package com.zhen.highlight_springmvc4.domain;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:16
     */
    public class DemoObj {
        private Long id;
        private String name;
    
        public DemoObj(){ //jackson对对象和json做转换时一定需要此空构造
            super();
        }
    
        public DemoObj(Long id, String name){
            this.id = id;
            this.name = name;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    package com.zhen.highlight_springmvc4.web.ch4_3;
    
    import com.zhen.highlight_springmvc4.domain.DemoObj;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:19
     */
    @Controller //声明此类是一个控制器
    @RequestMapping("/anno") //映射此类的访问路径是/anno
    public class DemoAnnoController {
    
        @RequestMapping(produces = "text/plain;charset=UTF-8") //未标注路径,因此使用类级别路径/anno,produces定制返回的媒体类型
        public @ResponseBody String index(HttpServletRequest request){//接受HttpServletRequest作为参数
            return "urlL" + request.getRequestURL() + "can access";
        }
    
        @RequestMapping(value = "/pathvar/{str}", produces = "text/plain;charset=UTF-8")//接受路径参数
        public @ResponseBody String demoPathVar(@PathVariable String str, HttpServletRequest request){
            return "url:" + request.getRequestURL() + "can access, str: " + str;
        }
    
        @RequestMapping(value = "/requestParam", produces = "text/plain;charset=UTF-8")
        public @ResponseBody String passRequestParam(Long id, HttpServletRequest request){//注入基本类型
            return "url: " + request.getRequestURL() + " can access, id: " + id;
        }
    
        @RequestMapping(value = "/obj", produces = "text/plain;charset=UTF-8")
        public @ResponseBody String passObj(DemoObj obj, HttpServletRequest request) {//注入对象类型
            return "url: " + request.getRequestURL() + " can access, obj id: " + obj.getId() + " obj name: " + obj.getName();
        }
    
        @RequestMapping(value = { "/name1", "/name2"}, produces = "text/plain;charset=UTF-8") //多个路径映射到统一url
        public @ResponseBody String remove(HttpServletRequest request) {
            return "url:" + request.getRequestURL() + " can access";
        }
    }
    package com.zhen.highlight_springmvc4.web.ch4_3;
    
    import com.zhen.highlight_springmvc4.domain.DemoObj;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:34
     */
    @RestController //组合注解,声明是控制器且返回数据时候不需要@ResponseBody
    @RequestMapping("/rest")
    public class DemoRestController {
    
        @RequestMapping(value = "getJson", produces = {"application/json;charset=UTF-8"}) //返回json
        public DemoObj getJson(DemoObj obj){
            return new DemoObj(obj.getId()+1, obj.getName() + "yy");
        }
    
    
        @RequestMapping(value = "/getXml", produces = "application/xml;charset=UTF-8") //返回xml
        public DemoObj getXml(DemoObj obj){
            return new DemoObj(obj.getId()+1, obj.getName() + "yy");
        }
    }
    View Code

    3、Spring MVC基本配置

    Spring MVC的定制配置需要配置类集成WebMvcConfigureAdapter,且在这个类使用@EnableWebMvc注解

    静态资源配置(让静态资源不被拦截):

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");//addResourceLocation指的是文件放置的位置,addResourceHandler指的是对外暴露的路径
        }

    拦截器配置:

    package com.zhen.highlight_springmvc4.interceptor;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:52
     */
    public class DemoInterceptor extends HandlerInterceptorAdapter { //集成HandlerInterceptorAdapter实现自定义拦截器
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //请求前执行
            long startTime = System.currentTimeMillis();
            request.setAttribute("startTime", startTime);
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //请求后执行
            long startTime = (Long) request.getAttribute("startTime");
            request.removeAttribute("startTime");
            Long endTime = System.currentTimeMillis();
            System.out.println("本次请求处理时间为:" + new Long(endTime
             - startTime) + "ms");
            request.setAttribute("handlingTime", endTime - startTime);
        }
    }
    
    
        @Bean
        public DemoInterceptor demoInterceptor(){ //配置拦截器的bean
            return new DemoInterceptor();
        }
        @Override
        public void addInterceptors(InterceptorRegistry registry) { //重写addInterceptors方法,注册拦截器
            registry.addInterceptor(demoInterceptor());
        }
    View Code

    @ControllerAdvice,将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效

    package com.zhen.highlight_springmvc4.advice;
    
    import org.springframework.ui.Model;
    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.InitBinder;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.context.request.WebRequest;
    import org.springframework.web.servlet.ModelAndView;
    
    /**
     * @author zhen
     * @Date 2018/7/3 11:16
     */
    @ControllerAdvice //@ControllerAdvice声明一个控制器建言
    public class ExceptiopnHandlerAdvice {
    
        @ExceptionHandler(value = Exception.class) //定义全局处理,通过@Exception的value属性过滤拦截条件
        public ModelAndView exception(Exception exception, WebRequest request) {
            ModelAndView modelAndView = new ModelAndView("error");//error页面
            modelAndView.addObject("errorMessage", exception.getMessage());
            return modelAndView;
        }
    
        @ModelAttribute //使用@ModelAttribute注解将键值对添加到全局
        public void addAttributes(Model model){
            model.addAttribute("msg", "额外信息");
        }
    
        @InitBinder //通过@InitBinder注解定制WebDataBinder
        public void initBinder(WebDataBinder webDataBinder) {
            webDataBinder.setDisallowedFields("id"); //忽略request参数的id
        }
    }
    
    package com.zhen.highlight_springmvc4.web.ch4_4;
    
    import com.zhen.highlight_springmvc4.domain.DemoObj;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @author zhen
     * @Date 2018/7/3 11:21
     */
    @Controller
    public class AdviceController {
    
        @RequestMapping("/advice")
        public String getSomething(@ModelAttribute("msg") String msg, DemoObj obj){
            throw new IllegalArgumentException("非常抱歉,参数有误/" + "来自@ModelAttribute:" + msg);
        }
    }
    
    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 11:24
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <html>
    <head>
        <title>@ControllerAdvice Demo</title>
    </head>
    <body>
        ${errorMessage}
    </body>
    </html>
    View Code

    其他配置:

      快捷的viewController:

    配置页面转向用到代码: 
    @RequestMapping("/index") //@RequestMapping配置URL和方法之间的映射 public String hello(){ return "index"; //通过ViewResolver的Bean配置,返回值为index,说明页面放置的路径为/WEB-INF/classes/views/index.jsp }
    可以通过在配置中重写addViewControllers简化配置:
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/index").setViewName("/index");
    registry.addViewController("/toUpload").setViewName("/upload");
    registry.addViewController("/converter").setViewName("/converter");
    registry.addViewController("/sse").setViewName("/sse");
    registry.addViewController("/async").setViewName("/async");
    }

      路径匹配参数配置:

      在Spring MVC中,路径参数如果带“.”的话,后面的值将忽略,可冲击感谢configurePathMatch方法则不忽略“.”后面的参数:

      

        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            configurer.setUseSuffixPatternMatch(false);
        }

    4、spring MVC的高级配置

      文件上传:

    添加依赖:
      <!-- file upload -->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
            </dependency>
            <!-- 非必须,简化io操作 -->
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.3</version>
            </dependency>
    上传页面:
    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 9:35
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>upload page</title>
    </head>
    <body>
    
        <div class="upload">
            <form action="upload" enctype="multipart/form-data" method="post">
                <input type="file" name="file"><br/>
                <input type="submit" value="上传">
            </form>
        </div>
    
    </body>
    </html>
    上传配置:
        @Bean
        public MultipartResolver multipartResolver(){
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
            multipartResolver.setMaxUploadSize(1000000);
            return multipartResolver;
        }
    控制器:
    package com.zhen.highlight_springmvc4.web.ch4_5;
    
    import org.apache.commons.io.FileUtils;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.File;
    import java.io.IOException;
    
    /**
     * @author zhen
     * @Date 2018/7/3 11:52
     */
    @Controller
    public class UploadController {
        @RequestMapping(value = "/upload", method = RequestMethod.POST)
        public @ResponseBody String upload(MultipartFile file){
            try{
                FileUtils.writeByteArrayToFile(new File("d:/temp/" + file.getOriginalFilename()), file.getBytes());
                return "ok";
            }catch (IOException e){
                e.printStackTrace();
                return "wrong";
            }
        }
    }
    View Code

      信息处理:

    HttpMessageConverter用来处理request和response里的数据。spring为我们内置了大量HttpMessageConverter。

    消息处理器:
    package com.zhen.highlight_springmvc4.messageconverter;
    
    import com.zhen.highlight_springmvc4.domain.DemoObj;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.HttpOutputMessage;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.AbstractHttpMessageConverter;
    import org.springframework.http.converter.HttpMessageNotReadableException;
    import org.springframework.http.converter.HttpMessageNotWritableException;
    import org.springframework.util.StreamUtils;
    
    import java.io.IOException;
    import java.nio.charset.Charset;
    
    /**
     * @author zhen
     * @Date 2018/7/3 13:37
     */
    public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj> { //继承AbstractHttpMessageConverter实现自定义的HttpMessageConverter
    
        public MyMessageConverter(){
            super(new MediaType("application", "x-wisely", Charset.forName("UTF-8"))); //新建自定义的媒体类型
        }
    
        @Override
        protected boolean supports(Class<?> aClass) {//表明只处理DemoObj这个类
            return DemoObj.class.isAssignableFrom(aClass);
        }
    
        @Override
        protected DemoObj readInternal(Class<? extends DemoObj> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException { //处理请求数据
            String temp = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8"));
            String[] tempArr = temp.split("-");
            return new DemoObj(new Long(tempArr[0]), tempArr[1]);
        }
    
        @Override
        protected void writeInternal(DemoObj demoObj, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {//处理输出数据
            String out = "hello:" + demoObj.getId() + "-" + demoObj.getName();
            httpOutputMessage.getBody().write(out.getBytes());
        }
    }
    配置处理器:
    
        @Bean
        public MyMessageConverter converter(){
            return new MyMessageConverter();
        }
    
        /*
         * 配置自定义的HttpMessageConverter两个方法:
         *  configureMessageConverters(重载会覆盖掉Spring MVC默认注册得多个HttpMessageConverter)
         *  extendMessageConverters(仅添加一个自定义的HttpMessageConverter,不覆盖默认的HttpMessageConverter)
         */
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters){
            converters.add(converter());
        }
    controller:
    package com.zhen.highlight_springmvc4.web.ch4_5;
    
    import com.zhen.highlight_springmvc4.domain.DemoObj;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * @author zhen
     * @Date 2018/7/3 13:51
     */
    @Controller
    public class ConverterController {
    
        @RequestMapping(value = "/convert", produces = { "application/x-wisely"})
        public @ResponseBody DemoObj convert(@RequestBody DemoObj demoObj){
            return demoObj;
        }
    }
    页面:
    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 11:24
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <html>
    <head>
        <title>HttpMessageConverter Demo</title>
    </head>
    <body>
        <div id="resp"></div>
        <input type="button" onclick="req();" value="请求"/>
    
        <script type="text/javascript" src="assets/js/jquery.min.js"></script>  <!-- 这里注意,script引入最好不要使用单闭合标签,可能会影响下面的脚本不被加载 -->
    <script>
        function req(){
            $.ajax({
                url: "convert",
                data: "1-wangyunfei",
                type: "POST",
                contentType: "application/x-wisely",
                success: function(data){
                    $("#resp").html(data);
                }
            });
        }
    </script>
    </body>
    </html>
    View Code

    服务器推送技术:

      早期是使用ajax轮询实现。

      本节方案基于:当客户端想服务端发送请求,服务端就会抓住这个请求不放,等数据跟新才返回给客户端

      基于SSE的服务器推送和基于servlet3+异步方法特征

    package com.zhen.highlight_springmvc4.web.ch4_5;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.Random;
    
    /**
     * @author zhen
     * @Date 2018/7/3 14:21
     */
    @Controller
    public class SseController {
    
        //这里输出媒体使用text/event-stream类型,是服务端SSE的支持
        @RequestMapping(value = "/push", produces="text/event-stream")
        public @ResponseBody String push(){
            Random r = new Random();
            try{
                Thread.sleep(5000);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
            return "data:Testing 1,2,3" + r.nextInt() + "
    
    ";
        }
    }
    
    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 11:24
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <html>
    <head>
        <title>SSE Demo</title>
    </head>
    <body>
        <div id="msgFrompPush"></div>
    
        <script type="text/javascript" src="assets/js/jquery.min.js"></script>
    <script type="text/javascript">
        if (!!window.EventSource){//EventSource对象只有新式的浏览器才有(Chrome、FireFox等),EventSource是SSE的客户端
            var source = new EventSource('push');
            s = '';
            source.addEventListener('message', function(e){//添加SSE监听,再此获取服务器推送的消息
                s += e.data + "<br/>";
                $("#msgFrompPush").html(s);
            });
    
            source.addEventListener('open', function(e){
               console.log("连接打开.");
            }, false);
    
            source.addEventListener('error', function(e){
                if (e.readyState == EventSource.CLOSED){
                    console.log("连接关闭");
                } else{
                    console.log(e.readyState);
                }
            }, false);
        } else{
            console.log("你的浏览器不支持SSE");
        }
    </script>
    </body>
    </html>
    SSE实现
    开启异步支持:
    package com.zhen.highlight_springmvc4;
    
    import org.springframework.web.WebApplicationInitializer;
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.servlet.DispatcherServlet;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration;
    
    /**
     * @author zhen
     * @Date 2018/7/3 10:00
     */
    public class WebInitializer implements WebApplicationInitializer {//WebApplicationInitializer是Spring用来配置Servlet3.0+配置的接口
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            context.register(MyMvcConfig.class);
            context.setServletContext(servletContext);//注册配置类
    
            ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));//注册Spring MVC的DispatcherServlet
            servlet.addMapping("/");
            servlet.setLoadOnStartup(1);
            servlet.setAsyncSupported(true);//开启异步方法支持
        }
    }
    
    控制器:
    package com.zhen.highlight_springmvc4.web.ch4_5;
    
    import com.zhen.highlight_springmvc4.service.PushService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.context.request.async.DeferredResult;
    
    /**
     * @author zhen
     * @Date 2018/7/3 14:58
     */
    @Controller
    public class AysncController {
        @Autowired
        PushService pushService;
    
        @RequestMapping("/defer")
        @ResponseBody
        public DeferredResult<String> deferredCall(){
            return pushService.getAsyncUpdate();
        }
    }
    
    定时任务:
    package com.zhen.highlight_springmvc4.service;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    import org.springframework.web.context.request.async.DeferredResult;
    
    /**
     * @author zhen
     * @Date 2018/7/3 14:57
     */
    @Service
    public class PushService {
    
        private DeferredResult<String> deferredResult;
    
        public DeferredResult<String> getAsyncUpdate(){
            deferredResult = new DeferredResult<String>();
            return deferredResult;
        }
    
        @Scheduled(fixedRate = 5000)
        public void refresh(){
            if (deferredResult != null) {
                deferredResult.setResult(new Long(System.currentTimeMillis()).toString());
            }
        }
    }
    页面:
    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 11:24
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <html>
    <head>
        <title>servlet async support</title>
    </head>
    <body>
    
    <script type="text/javascript" src="assets/js/jquery.min.js"></script>
    <script type="text/javascript">
        deferred();
        function deferred(){
            $.get('defer', function(data){
                console.log(data);
                deferred();
            });
        }
    </script>
    </body>
    </html>
    Servlet3.0+异步实现

    注意使用定时任务需要@EnableScheduling定时任务支持

    5、Spring MVC测试

    为了测试Web项目不启动项目,使用Serlet相关的模拟对象:如MockMVC、MockHttpServletRequest、MockHttpServletResponse、MockHttpSession等

    使用junit+spring testCOntext framework

    依赖:
     <!-- 测试依赖 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring-framework.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
    
    测试用例:
    package com.zhen.highlight_springmvc4.web.ch4_6;
    
    import com.zhen.highlight_springmvc4.MyMvcConfig;
    import com.zhen.highlight_springmvc4.service.DemoService;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.mock.web.MockHttpServletRequest;
    import org.springframework.mock.web.MockHttpSession;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.web.WebAppConfiguration;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    /**
     * @author zhen
     * @Date 2018/7/3 15:23
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {MyMvcConfig.class})
    @WebAppConfiguration("src/main/resources")
    public class TestControllerIntegrationTests {
    
        private MockMvc mockMvc;
    
        @Autowired
        private DemoService demoService;
    
        @Autowired
        private WebApplicationContext wac;
    
        @Autowired
        MockHttpSession session;
    
        @Autowired
        MockHttpServletRequest request;
    
        @Before
        public void setUp(){
            this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        }
    
        @Test
        public void testNormalController() throws Exception {
            mockMvc.perform(get("/normal")) //get发送一个请求,链接为/normal
                .andExpect(status().isOk()) //预期返回状态是200
                .andExpect(view().name("page")) //预期返回视图名为page
                .andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp")) //预期跳转地址为:/WEB-INF/classes/views/page.jsp
                .andExpect(model().attribute("msg", demoService.saySomething())); //预期model中的msg属性的值为hello
        }
    
        @Test
        public void testRestController() throws Exception{
            mockMvc.perform(get("/testRest"))
                .andExpect(status().isOk())
                .andExpect(content().contentType("text/plain;charset=UTF-8"))
                .andExpect(content().string(demoService.saySomething()));
        }
    
    }
    涉及controller:
    package com.zhen.highlight_springmvc4.web.ch4_6;
    
    import com.zhen.highlight_springmvc4.service.DemoService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author zhen
     * @Date 2018/7/3 16:01
     */
    @RestController
    public class MyRestController {
    
        @Autowired
        DemoService demoService;
    
        @RequestMapping(value = "/testRest", produces = "text/plain;charset=UTF-8")
        public String testRest(){
            return demoService.saySomething();
        }
    }
    package com.zhen.highlight_springmvc4.web.ch4_6;
    
    import com.zhen.highlight_springmvc4.service.DemoService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @author zhen
     * @Date 2018/7/3 15:59
     */
    @Controller
    public class NormalController {
        @Autowired
        DemoService demoService;
    
        @RequestMapping("/normal")
        public String testPage(Model model){
            model.addAttribute("msg", demoService.saySomething());
            return "page";
        }
    }
    
    涉及页面:
    <%--
      Created by IntelliJ IDEA.
      User: zhen
      Date: 2018/7/3
      Time: 11:24
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <html>
    <head>
        <title>Test page</title>
    </head>
    <body>
        <pre>
            Welcome to Spring MVC world
        </pre>
    </body>
    </html>
    View Code

       

  • 相关阅读:
    【爬坑】在 IDEA 中运行 Hadoop 程序 报 winutils.exe 不存在错误解决方案
    【爬坑】Vim 文档加密 & 解密
    Maven 安装配置
    2014/11/23 条件查询
    2014/11/21
    2014/11/20 SQL简单命令
    2014/11/19 SQL Server基础
    7、数组
    6、循环、跳转、异常语句,string类、math、datetime
    5、循环语句、穷举
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/9259854.html
Copyright © 2020-2023  润新知