1.功能
(1)文件上传配置
(2)自定义的HttpMessageConverter
(3)服务器端推送技术
2.文件上传配置
(1)概念
文件上传是常用功能,通过MuitipartResolver来上传文件。通过MultipartFile file来接受文件,通过MultipartFiles[] files 来接受多个文件
(2)示例
<?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.wisely</groupId>
<artifactId>hightlight_springmvc7</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>hightlight_springmvc7 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
<build>
<finalName>hightlight_springmvc7</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<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>
</plugins>
</pluginManagement>
</build>
</project>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>upload File</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>
注:multipartResolver必须是这个名字,不能变
//快捷viewController
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("/index");
registry.addViewController("/toUpload").setViewName("/upload");
}
//文件上传
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(1000000);
return resolver;
}
package com.wisely.highlight_springmvc7.web.chi4_5;
import java.io.File;
import java.io.IOException;
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;
@Controller
public class UploadController {
@RequestMapping(value="/upload",method= RequestMethod.POST)
public @ResponseBody String upload(MultipartFile file){
try {
FileUtils.writeByteArrayToFile(new File("D:/eclipse/1/"+file.getOriginalFilename()), file.getBytes());
return "ok";
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "wrong";
}
}
}
3.自定义HttpMessageConverter
(1)概念
HttpMessageConverter是用来处理request和response里的数据的。下面演示自定义的HttpMessageConverter,并注册这个HttpMessageConverter到SpringMvc
(2)示例
package com.wisely.highlight_springmvc7.messageConverter;
import java.io.IOException;
import java.nio.charset.Charset;
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 com.wisely.highlight_springmvc7.domain.DemoObj;
public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj> {
public MyMessageConverter(){
//新建一个自定义的媒体类型application/x-wisely
super(new MediaType("application","x-wisely",Charset.forName("UTF-8")));
}
//处理请求的数据。处理用“-”隔开的数据,并转成DemoObj对象
@Override
protected DemoObj readInternal(Class<? extends DemoObj> clazz,
HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
String temp = StreamUtils.copyToString(inputMessage.getBody(), Charset.forName("UTF-8"));
String[] tempArr = temp.split("-");
return new DemoObj(new Long(tempArr[0]),tempArr[1]);
}
//只处理DemoObj这个类
@Override
protected boolean supports(Class<?> clazz) {
return DemoObj.class.isAssignableFrom(clazz);
}
//处理输出数据。原样输出前面加hello
@Override
protected void writeInternal(DemoObj obj, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
String out = "hello:"+obj.getId()+"-"+obj.getName();
outputMessage.getBody().write(out.getBytes());
}
}
//快捷viewController
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("/index");
registry.addViewController("/toUpload").setViewName("/upload");
registry.addViewController("/converter").setViewName("/converter");
}
@Bean
public MyMessageConverter converter(){
return new MyMessageConverter();
}
//配置自定义的HttpMessageConverter
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
}
package com.wisely.highlight_springmvc7.web.chi4_5;
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;
import com.wisely.highlight_springmvc7.domain.DemoObj;
@Controller
public class ConverterController {
//指定返回的媒体类型为自定义的application/x-wisely
@RequestMapping(value="/convert",produces={"application/x-wisely"})
public @ResponseBody DemoObj convert(@RequestBody DemoObj demoObj){
return demoObj;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div id="resp"></div>
<input type="button" onclick="req();" value="请求"/>
<script type="text/javascript" src="assets/js/jquery-3.4.1.js"></script>
<script type="text/javascript">
function req(){
$.ajax({
url:"convert",
data:"1-penggege",
type:"POST",
contentType:"application/x-wisely",
success:function(data){
$("#resp").html(data);
}
});
}
</script>
</body>
</html>
4.服务器端推送技术
(1)概念
以前的办法是使用ajax向服务器轮询消息,使浏览器尽可能第一时间获得服务器的消息。但是这样轮询频率不好控制,增大了服务器压力。
现在服务器推送方案基于:当客户端向服务器发送请求后,服务器会抓住这个请求不放,等有数据更新的时候才返回客户端。客户端收到消息后,再向服务器发送请求。周而复始,可大大减少服务器的请求数量。
示例两种方法:
方法一:SSE(服务端发送事件)
方法二:基于Servlet3.0+的异步方法特性
还可以通过双向通信技术:WebSocket。在SpringBoot中演示
(2)示例1:SSE(服务端发送事件)
package com.wisely.highlight_springmvc7.web.chi4_5;
import java.util.Random;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "data:Test 1,2,3,"+r.nextInt()+"\n\n";
}
}
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SSE Demo</title>
</head>
<body>
<div id="msgFromPush"></div>
<script type="text/javascript" src="assets/js/jquery-3.4.1.js"></script>
<script type="text/javascript">
if(!!window.EventSource){
var source = new EventSource('push');//SSE的客户端,只有新式浏览器才有
s='';
source.addEventListener('message',function(e){
s+=e.data+"<br/>";
$("#msgFromPush").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>
//快捷viewController
@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");
}
(3)示例2:基于Servlet3.0+的异步方法特性
package com.wisely.highlight_springmvc7;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
/**
* 实现WebApplicationInitializer可以替代xml
*/
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MyMvcConfig.class);
context.setServletContext(servletContext);//新建WebApplicationContext,注册配置类,并与servletContext关联
//注册SpringMVC的DispatcherServlet
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
servlet.setAsyncSupported(true);//开启异步方法支持
}
}
//快捷viewController
@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");
}
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>servlet async support</title>
</head>
<body>
<script type="text/javascript" src="assets/js/jquery-3.4.1.js"></script>
<script type="text/javascript">
deferred();
function deferred(){
$.get('defer',function(data){
console.log(data);
deferred();
});
}
</script>
</body>
</html>
package com.wisely.highlight_springmvc7.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
@Service
public class PushService {
private DeferredResult<String> deferredResult;
public DeferredResult<String> getAsyncUpdate(){
deferredResult = new DeferredResult<String>();
return deferredResult;
}
@Scheduled(fixedDelay=5000)
public void refresh(){
if(deferredResult != null){
deferredResult.setResult(new Long(System.currentTimeMillis()).toString());
}
}
}
package com.wisely.highlight_springmvc7.web.chi4_5;
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;
import com.wisely.highlight_springmvc7.service.PushService;
@Controller
public class AysncController {
@Autowired
PushService pushService;
@RequestMapping("/defer")
@ResponseBody
public DeferredResult<String> deferredCall(){
return pushService.getAsyncUpdate();
}
}