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

   

原文地址:https://www.cnblogs.com/aigeileshei/p/9259854.html