Spring MVC 04:数据的发送


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会默认劫持。

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上传一个文件夹

用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循环存储数据)

流程1

SpringMVC上传文件

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

流程2

具体代码如下:

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

Select file:

但是到这里服务器报了一个405错误,表明fileServer不支持这个PUT请求。

error405

原因:我们一般的网页是只读的,如果要配成可写的状态,需要在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错误。。。

错误409

原因是在FileServer中artifact生成的包没有出现uploads这个文件夹,这里手动添加上去就好了

此时就运行成功了,但是由于uploads是自己创建的文件夹,所以在Fileserver服务器重启以后这些数据又会消失


文章作者: 银色回廊
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 银色回廊 !
评论
  目录