Spring MVC 04:数据的发送
显示图片
在进行Spring MVC的配置时,通常我们会配置一个dispatcher servlet用于处理对应的URL。配置如下:
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
只拦截.do请求配置如下:
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
当你在一个jsp写好<img>后,是无法直接显示的,因为MVC会默认劫持。

index.jsp
Hello World!
To Test11
这表示名字为 SpringMVC 的servlet会处理一切的url对应的请求,那么我们怎么让servlet来处理项目中的静态资源呢?这里有两种方法。
第一种方法(推荐使用):需要在SpringMVC的配置文件中配置resource。
SpringMVC.xml
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc = "http://www.springframework.org/schema/mvc"
xmlns:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation = "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- <bean name="/hello" class="cn.silverCorridors.HelloWorldController"></bean>-->
<!--扫描包-->
<context:component-scan base-package="cn.silverCorridors"></context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置视图 前缀:prefix 后缀:suffix-->
<property name="prefix" value="/Jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.silverCorridors.SpringToDateConverter"></bean>
</set>
</property>
</bean>
<!-- 通知给MVC配置了conversion-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!--mapping: URL 中的路径 location: 实际存储的路径 -->
<mvc:resources mapping="/img/**/" location="/img/"></mvc:resources>
</beans>
这样图片就显示成功

第二种方法: 另外使用一个servlet来处理静态资源。若我们的资源放置在webapps文件夹下的resources文件夹中,那么我们可以用名字为default的servlet来处理静态资源。因此我们还需要在上述配置的基础上加上以下配置:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>resources/*</url-pattern>
</servlet-mapping>
这表示default的servlet会处理url中为resources/*的对应的请求。这样,当你把你的image,css已经其他文件放在resources文件中时,spring就可以找到它啦。
AJAX访问 VS URL访问
普通的URL访问:通过URL访问网站返回一个HTML网页。
AJAX访问:发送一个请求,返回一个内容(不一定是页面,还有可能是JSON数据),很多时候,发过去的Request含有JSON,Response发送回来的也是JSON,并且整个过程不会刷新浏览器。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
// AJAX vs URL 访问 不刷新
// Request:Header,JSON -> Class(Pabc1)
// Response: Class -> JSON
// /param/test9
// POST Body : 用于接收JSON
@RequestMapping("/test7")
public @ResponseBody Pabc1 test7(@RequestBody Pabc1 pabc1) {
System.out.println("test7()");
System.out.println("pabc= " + pabc1);
pabc1.setA("Changed A");
return pabc1; // Class -> JSON
}
<script type="text/javascript">
$(document).ready(function () {
// 为#btn绑定事件函数
$('#btn').on('click',function () {
var p = { };
p.a = 'aaaa';
p.b = '555';
p.c = '777';
p.pd = {};
var pd = p.pd;
pd.d1 = '111';
pd.d2 = '222';
p.listPd = [];
var listPd = p.listPd;
listPd[0] = {};
listPd[0].d1 = '111';
listPd[0].d2 = '222';
p.mapPd = {};
var mapPd = p.mapPd;
mapPd.a = {};
mapPd.a.d1 = '111';
mapPd.a.d2 = '222';
// console.log(JSON.stringify(p));
$.ajax({
type: 'POST',
url: '/SpringMVCDemo01_war_exploded/resp/test7',
contentType: 'application/json;charset=UTF-8',
dataType: 'json',
data: JSON.stringify(p),
success: function (data) {
console.log(data);
},
error: function () {
console.log('error');
}
})
});
});
</script>
文件上传(单个文件)
Servlet原生的方法
需要的jar包:commons-FileUpload、commons-io
下面是示例:
在index.jsp新建一个form表单来进行提交文件:
<form action="/SpringMVCDemo01_war_exploded/uploader/test1" method="post" enctype="multipart/form-data">
Select file:<input type="file" name="upfile"/>
<input type="submit" value="upload"/>
</form>
创建对应的Controller类用于处理接收的数据
@Controller
@RequestMapping("/uploader")
public class Uploader {
@RequestMapping("/test1")
public String test1(HttpServletRequest request) throws Exception {
System.out.println("test1()");
// 用于保存文件的文件夹
String path = request.getSession().getServletContext().getRealPath("/upload/");
File dir = new File(path);
if (!dir.exists()){ // 如果文件夹不存在,创建
dir.mkdir();
}
// 从request中分离出file,挨个保存
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> files = upload.parseRequest(request);
for (FileItem file : files)
{
if (!file.isFormField()){//如果不是表单元素(Form Field),说明是上传的文件
String fileName = file.getName();
file.write(new File(path,fileName)); // 将接收到的文件写入path目录下
file.delete();
}
}
return "jsp1";
}
}
运行结果:


或者用Postman上传一个文件夹

使用UUID来产生不会重名的文件
@RequestMapping("/test1")
public String test1(HttpServletRequest request) throws Exception {
System.out.println("test1()");
// 用于保存文件的文件夹
String path = request.getSession().getServletContext().getRealPath("/upload/");
File dir = new File(path);
if (!dir.exists()){ // 如果文件夹不存在,创建
dir.mkdir();
}
// 从request中分离出file,挨个保存
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> files = upload.parseRequest(request);
for (FileItem file : files)
{
if (!file.isFormField()){//如果不是表单元素(Form Field),说明是上传的文件
String fileName = file.getName();
// 使用UUID
String uuid = UUID.randomUUID().toString().replace("-","");
fileName = uuid + "_" + fileName;
file.write(new File(path,fileName)); // 将接收到的文件写入path目录下
file.delete();
}
}
return "jsp1";
}

在上面原生的JAVAWEB上传文件中,具体流程:
browser发出请求提交给Server,Serlvet处理执行(准备dirs,parse,for循环存储数据)

SpringMVC上传文件
如果是SpringMVC的方式,可以将servlet中的parse步骤省略,它会调用一个叫文件解析器(file resolver)的东西。流程如下:

具体代码如下:
SpringMVC.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
创建对应的Controller类用于处理接收的数据
@RequestMapping("/test2")
public String test2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("test2()");
// 用于保存文件的文件夹
String path = request.getSession().getServletContext().getRealPath("/upload/");
File dir = new File(path);
if (!dir.exists()){ // 如果文件夹不存在,创建
dir.mkdir();
}
// 说明不是Form Field , 说明是上传的文件
// 使用UUID
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
// 将接收到的文件写入path目录下
upload.transferTo(new File(path,filename));
return "jsp1";
}

同理,以上操作用Postman也是可以完成的
文件上传(多个文件)
Servlet原生的方法
取消SpringMVC.xml的multipartResolver绑定
在form表单的属性上添加multiple属性
<form action="/SpringMVCDemo01_war_exploded/uploader/test1" method="post" enctype="multipart/form-data">
Select file:<input type="file" multiple="multiple" name="upfile"/>
<input type="submit" value="upload"/>
</form>
上传文件:

上传成功:

SpringMVC的方法
SpringMVC就不需要这么麻烦了,只需要在原来test2方法的基础上,将MultipartFile改为MultipartFile[]数组进行读取文件就可以了
@RequestMapping("/test3")
public String test3(HttpServletRequest request,@RequestParam("upfile") MultipartFile[] files) throws Exception {
System.out.println("test3()");
// 用于保存文件的文件夹
String path = request.getSession().getServletContext().getRealPath("/upload/");
File dir = new File(path);
if (!dir.exists()){ // 如果文件夹不存在,创建
dir.mkdir();
}
// 说明不是Form Field , 说明是上传的文件
// 使用UUID
for (MultipartFile file : files) {
String filename = file.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
// 将接收到的文件写入path目录下
file.transferTo(new File(path,filename));
}
return "jsp1";
}
SpringMVC跨服务器上传文件
通过一个tomcat服务器(Demo01)将文件写到另一个tomcat文件服务器(FileServer)上
使用调用Jersey客户端API来实现这种RestFul风格的Web服务
pom.xml导入jar包
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19.4</version>
</dependency>
利用Jersey客户端的RESTful Java客户端
创建一个客户类
Client client = Client.create(); // 配置客户端
说明:Client 类是创建一个 RESTful Web Service 客户端的主要配置点。你可以使用它来配置不同的客户端属性和功能,并且指出使用哪个资源提供者。创建一个 Client 类的实例是一个比较昂贵的操作,所以尽量避免创建一些不需要的客户端实例。
比较好的方式是尽可能地复用已经存在的实例。
2.当创建完 Client 类实例后,则可使用它。无论如何,在发出请求前,你需创建一个 Web Resource 对象来封装客户端所需要的 Web 资源。Web 资源创建了一个 WebResponse 对象:
import com.sun.jersey .api.client.WebResource;
Web Resource webResource = c.resource("http://example.com/base");
说明:通过使用 WebResource 对象来创建要发送到 Web 资源的请求,以及处理从 Web 资源返回的响应。
例如,你可以使用 WebResource 对象来发送 HTTP GET、PUT、POST 以及 DELETE 请求。
一个tomcat接收文件并把该文件发送到另一个tomcat服务器的具体实例:
@RequestMapping("/test4")
public String test4(HttpServletRequest request, MultipartFile upfile) throws Exception {
System.out.println("test4()");
// 用于保存文件的文件夹
String path = "http://localhost:8081/fileServer_war/uploads";
// 说明不是Form Field , 说明是上传的文件
// 使用UUID
String filename = upfile.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
// 将接收到的文件写入FileServer 这个客户端
Client client = Client.create(); // 配置客户端
WebResource webResource = client.resource(path + filename); //找到另一台服务器的path下的文件目录,并放入资源
webResource.put(upfile.getBytes());//put请求
return "jsp1";
}
index.jsp
但是到这里服务器报了一个405错误,表明fileServer不支持这个PUT请求。

原因:我们一般的网页是只读的,如果要配成可写的状态,需要在web.xml配置
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value><!--把网页的默认只读改为false-->
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
此时又会出现409错误。。。

原因是在FileServer中artifact生成的包没有出现uploads这个文件夹,这里手动添加上去就好了
此时就运行成功了,但是由于uploads是自己创建的文件夹,所以在Fileserver服务器重启以后这些数据又会消失