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.</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-</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-</project.reporting.outputEncoding> <!-- Web -->
<jsp.version>2.2</jsp.version>
<jstl.version>1.2</jstl.version>
<servlet.version>3.1.</servlet.version> <!-- Spring -->
<spring-framework.version>4.1..RELEASE</spring-framework.version> <!-- Logging -->
<logback.version>1.0.</logback.version>
<slf4j.version>1.7.</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.</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.</version>
</dependency> <!-- file upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.</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.</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..v20170317</version>
<configuration>
<httpConnector>
<port></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{} - %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: //
Time: :
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();
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();
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.</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()+, obj.getName() + "yy");
} @RequestMapping(value = "/getXml", produces = "application/xml;charset=UTF-8") //返回xml
public DemoObj getXml(DemoObj obj){
return new DemoObj(obj.getId()+, obj.getName() + "yy");
}
}

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());
}

@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: //
Time: :
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>

其他配置:

  快捷的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.</version>
</dependency>
<!-- 非必须,简化io操作 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
上传页面:
<%--
Created by IntelliJ IDEA.
User: zhen
Date: //
Time: :
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();
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";
}
}
}

信息处理:

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[]), tempArr[]);
} @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: //
Time: :
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>

服务器推送技术:

  早期是使用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();
} catch (InterruptedException e){
e.printStackTrace();
}
return "data:Testing 1,2,3" + r.nextInt() + "\n\n";
}
} <%--
Created by IntelliJ IDEA.
User: zhen
Date: //
Time: :
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();
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 = )
public void refresh(){
if (deferredResult != null) {
deferredResult.setResult(new Long(System.currentTimeMillis()).toString());
}
}
}
页面:
<%--
Created by IntelliJ IDEA.
User: zhen
Date: //
Time: :
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: //
Time: :
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>

   

springboot学习章节代码-Spring MVC基础的更多相关文章

  1. springboot学习章节代码-spring基础

    1.DI package com.zhen.highlights_spring4.ch1.di; import org.springframework.stereotype.Service; /** ...

  2. springboot学习章节代码-spring高级话题

    1.Spring Aware(获取Spring容器的服务) hi, i am guodaxia! test.txt package com.zhen.highlights_spring4.ch3.aw ...

  3. Spring MVC 基础

    Spring MVC 基础 1.Web MVC基础 MVC的本质是表现层模式,我们以视图模型为中心,将视图和控制器分离出来.就如同分层模式一样,我们以业务逻辑为中心,把表现层和数据访问层代码分离出来是 ...

  4. Spring MVC——基础(简介,使用,地址映射)

    Spring MVC简介 重点Spring MVC的处理流程 Spring MVC特点 Spring MVC的使用 将相应的JAR包导入lib文件下 配置相关webxml 配置servlet-mvcx ...

  5. 。。。在学习新框架Spring MVC的感受。。。

    已经学习一遍Spring MVC了,感觉还是懵懵懂懂的,特别是重定向,路径,参数的这些问题,心好乱,不过,这,都不是问题!!! 继续努力,努力到会为止!!!加油!!!

  6. Spring MVC基础学习

    SpringMVC是Spring框架的一个模块,无需通过中间层整合在一起.SpringMVC是一个基于MVC设计模式web框架,MVC-model-view-controller:MVC将服务器端分为 ...

  7. Spring MVC基础了解

    参考网址:https://www.yiibai.com/spring_mvc/springmvc_overview.html Spring框架相关 Spring Security 一个灵活强大的身份验 ...

  8. Spring MVC 基础注解之@RequestMapping、@Controller、(二)

    我现在学的是spring4.2 今天主要学习了Spring MVC注解 引入注解可以减少我们的代码量,优化我们的代码. @Controller:用于标识是处理器类: @RequestMapping:请 ...

  9. Spring MVC基础

    1.Web MVC基础 MVC的本质是表现层模式,我们以视图模型为中心,将视图和控制器分离出来.就如同分层模式一样,我们以业务逻辑为中心,把表现层和数据访问层代码分离出来是一样的方法.框架只能在技术层 ...

随机推荐

  1. RLE Plots: relative log expression

    RLE Plots: Visualising Unwanted Variation in High Dimensional Data 参考:RLE Plots: Visualising Unwante ...

  2. java开学第一周测试代码

    Account.java /* 信1705-3 20173612  陈阳阳 */package ATM; public class Account { private String accountID ...

  3. webpack添加热更新

    之前的wbepack一直没有加上热更新,这是一种遗憾,今天终于加上去了,看不懂我博客的可以看这篇文章:http://blog.csdn.net/hyy1115/article/details/5302 ...

  4. elasticsearch查询语句

    1,安装es 安装java环境 # java --versionjava version "1.8.0_65" Java(TM) SE Runtime Environment (b ...

  5. 网络管理命令ping和arping

    ping ping        向目标主机发送icmp请求包 常用来测试当前主机与目标主机网络连接状况 常见选项 -c              设置发包的个数 -s               设 ...

  6. MySql之安装以及设置密码等

    1.MySQL的下载安装.简单应用及目录介绍 1.下载安装 windows10的:https://www.cnblogs.com/clschao/articles/9916971.html linux ...

  7. Vue之单文件组件的数据传递,axios请求数据及路由router

    1.传递数据 例如,我们希望把父组件的数据传递给子组件. 可以通过props属性来进行传递. 传递数据三个步骤: 步骤1:在父组件中,调用子组件的组名处,使用属性值的方式往下传递数据 <Menu ...

  8. SWUST OJ(952)

    单链表的插入操作实现 #include <stdio.h> #include <stdlib.h> typedef struct LinkList { int data; st ...

  9. Spring中添加新的配置表,并对新的配置表进行处理

    实习过程中boss交代的任务(以下出现的代码以及数据只给出小部分,提供一个思路) 目的:Spring中添加新的配置表,并对新的配置表进行处理:替换的新的配置表要友好,同时保证替换前后功能不能发生变化. ...

  10. 廖雪峰网站:学习python函数—定义函数(二)

    def my_abs(x): if x >= 0: return x else: return -x print(my_abs(-99)) # 空函数 def nop(): pass # 参数检 ...