跳到正文
返回

从 0 开始的 SpringMVC 学习

发表于 更新于
浏览量: --

封面画师:T5-茨舞(微博)     封面ID:66855568

1. SpringMVC

1.1 SpringMVC 执行原理

MVC执行流程

  1. 用户发送请求到前端控制器 DispatcherServlet。
  2. DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
  3. 处理器映射器根据请求 url(配置的 bean 中的 name 和 class)找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。
  4. DispatcherServlet 通过 HandlerAdapter 处理器适配器调用处理器。
  5. 执行处理器(Controller,也叫后端控制器)。
  6. Controller 执行完成返回 ModelAndView。
  7. HandlerAdapter 将 Controller 执行结果 ModelAndView 返回给 DispatcherServlet。
  8. DispatcherServlet 将 ModelAndView 传给 ViewResolver 视图解析器。
  9. ViewResolver 解析后返回具体的 View。
  10. DispatcherServlet 对 View 进行渲染视图(即:将模型数据填充到视图中)。
  11. DispatcherServlet 响应结果。

1.2 RestFul 风格

2.1 功能

2.2 比较

传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get

使用 RESTful 操作资源:可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!

2.3 GET 与POST

  1. GET 后退按钮/刷新无害,POST 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。
  2. GET 书签可收藏,POST 为书签不可收藏。
  3. GET 能被缓存,POST 不能缓存。
  4. GET 编码类型 application/x-www-form-url,POST 编码类型 encodedapplication/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。
  5. GET 历史参数保留在浏览器历史中。POST 参数不会保存在浏览器历史中。
  6. GET 对数据长度有限制,当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。POST 无限制。
  7. GET 只允许 ASCII 字符。POST 没有限制。也允许二进制数据。
  8. 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET!POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。
  9. GET 的数据在 URL 中对所有人都是可见的。POST 的数据不会显示在 URL 中。
  10. GET 执行效率却比 POST 方法好。GET 是 form 提交的默认方法。

2.4 使用

SpringMVC 中配置文件常用书写方式(springmvc-servlet.xml ):

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--开启注解扫描,只扫描controller-->
    <context:component-scan base-package="com.yang">
    <!-- <context:component-scan base-package="com.yang.controller"/> -->
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller">
        </context:include-filter>
    </context:component-scan>

    <!--配置视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--过滤静态资源-->
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/images/**" location="/images/"/>

    <!--开启SpringMVC注解的支持-->
    <!--
		在SpringMVC中一般采用@RequestMapping注解来完成映射关系
        要想使@RequestMapping注解生效
        必须向上下文中注册DefaultAnnotationHandlerMapping
        和一个AnnotationMethodHandlerAdapter实例
        这两个实例分别在类级别和方法级别处理。
        而annotation-driven配置帮助我们自动完成上述两个实例的注入。
     -->
    <mvc:annotation-driven/>

    <!--静态资源过滤-->
    <mvc:default-servlet-handler/>
</beans>

配置 web.xml,注册 DispatcherServlet:

<!--DispatchServlet-->
<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:applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--/ 匹配所有的请求;(不包括.jsp)-->
    <!--/* 匹配所有的请求;(包括.jsp)-->
    <url-pattern>/</url-pattern>
</servlet-mapping>

如果使用 <url-pattern>/*</url-pattern>,会出现返回 jsp 视图 时再次进入 SpringMVC 的 DispatcherServlet 类,导致找不到对应的 Controller 而报 404 错。


RestFul 风格的使用(省略界面的编写):

//映射访问路径
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable String p2, Model model){
    String result = p1+p2;
    //Spring MVC会自动实例化一个Model对象用于向视图中传值
    model.addAttribute("msg", "结果:"+result);
    //返回视图位置
    return "test";
}
//映射访问路径,必须是Get请求
@RequestMapping(value = "/hello",method = {RequestMethod.GET})
public String index2(Model model){
    model.addAttribute("msg", "hello!");
    return "test";
}

2.5 小结

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

@GetMapping 是一个组合注解

它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。


1.3 转发和重定向

3.1 区别

  1. 地址栏不发生变化

  2. 只有一个请求响应

  3. 可以通过 request 域传递数据

  4. 只能跳转本站点资源

  5. 服务器端行为

  1. 地址栏会发生变化

  2. 两次请求响应

  3. 无法通过 request 域传递对象

  4. 可以跳转到任意 URL

  5. 客户端行为

3.2 SpringMVC中的使用

默认有视图解析器:

@Controller
public class ResultSpringMVC {
    @RequestMapping("/test/t1")
    public String test1(){
        //转发forward
        return "test";
        //return "forward:/WEB-INF/pages/test.jsp"
    }

    @RequestMapping("/test/t2")
    public String test2(){
        //重定向redirect
        return "redirect:/index.jsp";	//不需要加项目名,框架已经帮你自动完成
        //return "redirect:hello.do"; //hello.do为另一个请求/
    }
}

1.4 数据处理

4.1 处理提交数据

//@RequestParam("username") : username提交的域的名称 .
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
    System.out.println(name);
    return "hello";
}

4.2 数据显示到前端

Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;

ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;

ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
@RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        System.out.println("testModelAndView方法执行了。。。");
        //模拟从数据库中查询User对象
        ModelAndView mv = new ModelAndView();
        User user = new User();
        user.setUsername("小王");
        user.setPassword("789654");
        user.setAge(12);
        //把user对象存储到mv对象中,也会把user对象存入到request对象
        mv.addObject("user",user);

        //跳转的界面 使用视图解析器
        mv.setViewName("success");
        return mv;
    }
/***************************************************************************************/
<a href="user/testModelAndView">testModelAndView</a><br/>

4.3 解决乱码问题

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

4.4 数据格式转换

public class StringToDateConverter implements Converter<String, Date> {
    /**
     * String source 传入字符串
     * @param source
     * @return
     */
    public Date convert(String source) {
        //判断
        if(source == null){
            throw new RuntimeException("请传入数据");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            //把字符串转换成日期
            return df.parse(source);
        } catch (Exception e) {
            throw new RuntimeException("数据类型转换错误");
        }
    }
}
<!--配置自定义类型转换器-->
    <bean id="connectorServerFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.yang.utils.StringToDateConverter"/>
            </set>
        </property>
    </bean>

<!--开启SpringMVC框架注解的支持-->
<mvc:annotation-driven conversion-service="connectorServerFactoryBean"/>

4.5 Servlet原生API的使用

1.5 JSON

5.1 Jackson

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.0</version>
</dependency>

简单测试

@Controller
public class UserController {
    @RequestMapping("/json1")
    @ResponseBody
    public String json1() throws JsonProcessingException {
        //创建一个jackson的对象映射器,用来解析数据
        ObjectMapper mapper = new ObjectMapper();
        //创建一个对象
        User user = new User("小明", 13, "男");
        //将我们的对象解析成为json格式
        String str = mapper.writeValueAsString(user);
        //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
        return str;
    }
}
//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        </bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="failOnEmptyBeans" value="false"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

输出时间对象:

​ Controller:

@RequestMapping("/json2")
public String json2() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    //创建时间一个对象,java.util.Date
    Date date = new Date();
    //将我们的对象解析成为json格式
    String str = mapper.writeValueAsString(date);
    return str;
}

​ 运行结果:

@RequestMapping("/json3")
public String json3() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    //不使用时间戳的方式
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    //自定义日期格式对象
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //指定日期格式
    mapper.setDateFormat(sdf);

    Date date = new Date();
    String str = mapper.writeValueAsString(date);

    return str;
}

抽取为工具类

public class JsonUtils {
    
    public static String getJson(Object object) {
        return getJson(object,"yyyy-MM-dd HH:mm:ss");
    }

    public static String getJson(Object object,String dateFormat) {
        ObjectMapper mapper = new ObjectMapper();
        //不使用时间差的方式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //自定义日期格式对象
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        //指定日期格式
        mapper.setDateFormat(sdf);
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

5.2 FastJson

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
</dependency>

测试类

public class FastJsonDemo {
    public static void main(String[] args) {
        //创建一个对象
        User user1 = new User("ONE", 13, "男");
        User user2 = new User("TWO", 13, "男");
        User user3 = new User("THREE",13, "男");
        User user4 = new User("FOUR", 13, "男");
        List<User> list = new ArrayList<User>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);

        System.out.println("*******Java对象 转 JSON字符串*******");
        String str1 = JSON.toJSONString(list);
        System.out.println("JSON.toJSONString(list)==>"+str1);
        String str2 = JSON.toJSONString(user1);
        System.out.println("JSON.toJSONString(user1)==>"+str2);

        System.out.println("\n****** JSON字符串 转 Java对象*******");
        User jp_user1=JSON.parseObject(str2,User.class);
        System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);

        System.out.println("\n****** Java对象 转 JSON对象 ******");
        JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
        System.out.println("(JSONObject) 	
                           JSON.toJSON(user2)==>"+jsonObject1.getString("name"));

        System.out.println("\n****** JSON对象 转 Java对象 ******");
        User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
        System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
    }
}

1.6 Ajax

6.1 定义

6.2 jQuery.ajax

jQuery.ajax(...)
       部分参数
              url请求地址   <---主要---
             type请求方式GETPOST1.9.0之后用method
          headers请求头
             data要发送的数据	<---主要---
      contentType即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
            async是否异步
          timeout设置请求超时时间毫秒
       beforeSend发送请求前执行的函数(全局)
         complete完成之后执行的回调函数(全局)
          success成功之后执行的回调函数(全局)	<---主要---
            error失败之后执行的回调函数(全局)	<---主要---
          accepts通过请求头发送给服务器告诉服务器当前客户端课接受的数据类型
         dataType将服务器端返回的数据转换成指定类型
            "xml": 将服务器端返回的内容转换成xml格式
           "text": 将服务器端返回的内容转换成普通文本格式
           "html": 将服务器端返回的内容转换成普通文本格式在插入DOM中时如果包含JavaScript标签则会尝试去执行
         "script": 尝试将返回值当作JavaScript去执行然后再将服务器端返回的内容转换成普通文本格式
           "json": 将服务器端返回的内容转换成相应的JavaScript对象
          "jsonp": JSONP 格式使用 JSONP 形式调用函数时 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名以执行回调函数

案例一(使用 SpringMVC)

  1. 编写一个 AjaxController
@RestController
public class AjaxController {

    @RequestMapping("/a1")
    public void ajax1(String name , HttpServletResponse response) throws IOException {
        if ("admin".equals(name)){
            response.getWriter().print("true");
        }else{
            response.getWriter().print("false");
        }
    }

}
  1. 导入 jquery(在线的 CDN 与下载导入)
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="${pageContext.request.contextPath}/statics/js/jquery-1.12.4.min.js"></script>
  1. 编写 index.jsp 测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Ajax测试</title>
    <%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%>
    <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
    <script>
        function a1(){
            $.post({
                url:"${pageContext.request.contextPath}/a1",
                data:{'name':$("#txtName").val()},
                success:function (data,status) {
                    alert(data);
                    alert(status);
                }
            });
        }
    </script>
  </head>
  <body>
  <%--onblur:失去焦点触发事件--%>
  用户名:<input type="text" id="txtName" onblur="a1()"/>
  </body>
</html>
  1. 设置静态资源不被拦截
 <!--前端控制器,哪些静态资源不拦截-->
    <!--mapping后一定要有**,location后可以没有**-->
    <mvc:resources mapping="/static/js/**" location="/js/"/>

6.3 数据返回案例

  1. 实体类 User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
    private String sex;
}
  1. Controller 类
@RequestMapping("/a2")
public List<User> ajax2(){
    List<User> list = new ArrayList<User>();
    list.add(new User("admin",99,"男"));
    list.add(new User("boy",3,"男"));
    list.add(new User("girl",3,"女"));
    return list; //由于@RestController注解,将list转成json格式返回
}
  1. 前端界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<input type="button" id="btn" value="获取数据"/>
<table width="80%" align="center">
    <tr>
        <td>姓名</td>
        <td>年龄</td>
        <td>性别</td>
    </tr>
    <tbody id="content">
    </tbody>
</table>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
<script>
    $(function () {
        $("#btn").click(function () {
            $.post("${pageContext.request.contextPath}/a2",function (data) {
                console.log(data)
                var html="";
                for (var i = 0; i <data.length ; i++) {
                    html+= "<tr>" +
                        "<td>" + data[i].name + "</td>" +
                        "<td>" + data[i].age + "</td>" +
                        "<td>" + data[i].sex + "</td>" +
                        "</tr>"
                }
                $("#content").html(html);
            });
        })
    })
</script>
</body>
</html>

6.4 注册提示案例

  1. Controller
@RequestMapping("/a3")
public String ajax3(String name,String pwd){
    String msg = "";
    //模拟数据库中存在数据
    if (name!=null){
        if ("admin".equals(name)){
            msg = "OK";
        }else {
            msg = "用户名输入错误";
        }
    }
    if (pwd!=null){
        if ("123456".equals(pwd)){
            msg = "OK";
        }else {
            msg = "密码输入有误";
        }
    }
    return msg; //由于@RestController注解,将msg转成json格式返回
}
  1. 前端界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>ajax</title>
    <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
    <script>

        function a1(){
            $.post({
                url:"${pageContext.request.contextPath}/a3",
                data:{'name':$("#name").val()},
                success:function (data) {
                    if (data.toString()=='OK'){
                        $("#userInfo").css("color","green");
                    }else {
                        $("#userInfo").css("color","red");
                    }
                    $("#userInfo").html(data);
                }
            });
        }
        function a2(){
            $.post({
                url:"${pageContext.request.contextPath}/a3",
                data:{'pwd':$("#pwd").val()},
                success:function (data) {
                    if (data.toString()=='OK'){
                        $("#pwdInfo").css("color","green");
                    }else {
                        $("#pwdInfo").css("color","red");
                    }
                    $("#pwdInfo").html(data);
                }
            });
        }

    </script>
</head>
<body>
<p>
    用户名:<input type="text" id="name" onblur="a1()"/>
    <span id="userInfo"></span>
</p>
<p>
    密码:<input type="text" id="pwd" onblur="a2()"/>
    <span id="pwdInfo"></span>
</p>
</body>
</html>

1.7 路径匹配

7.1 /**和/*区别

WildcardDescription
匹配任何单字符
*匹配 0 或者任意数量的字符
**匹配 0 或者更多的目录
PathDescription
/app/*.x匹配所有在 app 路径下的.x 文件
/app/p?ttern匹配/app/pattern 和 /app/pXttern,但是不包括/app/pttern
/**/example匹配 /app/example, /app/foo/example, 和 /example
/app/**/dir/file.匹配/app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/**/*.jsp匹配任何的.jsp 文件
  1. /*:匹配一级,即 /add , /query 等
  2. /**:匹配多级,即 /add , /add/user, /add/user/user… 等

1.8 文件操作

8.1 文件下载

  1. 准备:导入文件上传的 jar 包,commons-fileupload,Maven 会自动帮我们导入他的依赖包 commons-io 包;
<!--文件上传-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
</dependency>
  1. 配置 bean(配置文件解析器):multipartResolver

注意!这个 bean 的 id 必须为:multipartResolver,否则上传文件会报 400 的错误!

<!--文件上传配置-->
<bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 请求的编码格式,必须和JSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
    <property name="defaultEncoding" value="utf-8"/>
    <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
    <property name="maxUploadSize" value="10485760"/>
    <property name="maxInMemorySize" value="40960"/>
</bean>

​ CommonsMultipartFile 的 常用方法:

  1. 下载步骤:
  1. 设置 response 响应头
  2. 读取文件 — InputStream
  3. 写出文件 — OutputStream
  4. 执行操作
  5. 关闭流 (先开后关)
  1. 代码实现:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
    //要下载的图片地址
    String  path = request.getServletContext().getRealPath("/upload");
    String  fileName = "基础语法.jpg";

    //1、设置response 响应头
    response.reset(); //设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8"); //字符编码
    response.setContentType("multipart/form-data"); //二进制传输数据
    //设置响应头
    response.setHeader("Content-Disposition",
            "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));

    File file = new File(path,fileName);
    //2、 读取文件--输入流
    InputStream input=new FileInputStream(file);
    //3、 写出文件--输出流
    OutputStream out = response.getOutputStream();

    byte[] buff =new byte[1024];
    int index=0;
    //4、执行 写出操作
    while((index= input.read(buff))!= -1){
        out.write(buff, 0, index);
        out.flush();
    }
    out.close();
    input.close();
    return null;
}
<a href="/download">点击下载</a>

8.2 文件上传

  1. 导入相关依赖(见 8.1.1
  2. 配置文件解析器:multipartResolver(见 8.1.2
  3. 代码实现:
    • 提交的表单,form 标签 method 属性值必须为 post,enctype 属性值必须为 multipart/form-data
<h3>SpringMVC文件上传</h3>
    <form action="fileUpload_2" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload">
        <input type="submit" value="上传">
    </form>
@RequestMapping("/fileUpload_2")
    public String fileUpload_2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("SpringMVC文件上传。。。");

        //使用fileupload组件上传文件
        //上传的位置
        String path = request.getSession().getServletContext().getRealPath("/upload/");
        System.out.println(path);
        //判断文件是否存在
        File file = new File(path);
        if (!file.exists()) {
            //创建文件夹
            file.mkdirs();
        }

        //说明上传文件项
        //获取上传文件名称
        String filename = upload.getOriginalFilename();
        //把文件名设置成唯一值
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "-" + filename;
        upload.transferTo(new File(path, filename));
        return "success";
    }

8.3 跨服务器上传文件

  1. 在 8.2 的环境下进行以下操作: 导入依赖,配置文件解析器

  2. 导入相关依赖:

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.18.1</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.18.1</version>
</dependency>
  1. 前端界面:
<h3>跨服务器文件上传</h3>
<form action="fileUpload_3" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload">
    <input type="submit" value="上传">
</form>
  1. 控制器代码:
@RequestMapping("/fileUpload_3")
    public String fileUpload_3(MultipartFile upload) throws Exception {
        System.out.println("SpringMVC文件上传。。。");
        //定义上传文件服务器路径
        String path = "http://localhost:9090/uploads/";
        //说明上传文件项
        //获取上传文件名称
        String filename = upload.getOriginalFilename();
        //把文件名设置成唯一值
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "-" + filename;
        //创建客户端对象
        Client client = Client.create();
        //和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);
        //上传文件
        webResource.put(upload.getBytes());
        return "success";
    }

1.9 异常处理

9.1 自定义异常处理流程

9.2 代码实现

  1. 控制器
@Controller
@RequestMapping("/user")
public class usercontroller {
    @RequestMapping("/testException")
    public String testException() throws SysException{
        System.out.println("testException执行了。。。");
        //模拟异常
        try {
            int a = 10/0;
        } catch (Exception e) {
            //打印异常信息
            e.printStackTrace();
            //抛出自定义异常信息
            throw new SysException("查询用户出现异常。。。");
        }
        return "success";
    }
}
  1. 自定义异常类
public class SysException extends Exception{
    //储存提示信息
    private String message;
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public SysException(String message) {
        this.message = message;
    }
}
  1. 自定义异常处理器(处理器类实现 HandlerExceptionResolver 接口)
public class SysExceptionResolver implements HandlerExceptionResolver {
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
        //获取异常对象
        SysException e = null;
        if(ex instanceof SysException){
            e = (SysException) ex;
        }else {
            e = new SysException("系统正在维护。。。");
        }
        //创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");
        return mv;
    }
}
  1. 配置异常处理器
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.yang.exception.SysExceptionResolver"/>
  1. 其他界面
<body>
    <h3>异常处理</h3>
    <a href="user/testException">异常处理</a>
</body>
/***************************************************************************************/
<body>
    ${errorMsg}
</body>

1.10 拦截器

拦截器过滤器
它是 SpringMVC 框架自己的,只有使用了 SpringMVC 的工程才可以使用它是 Servlet 规范中的一部分,任何 Java Web 工程都可以使用
只会拦截访问的控制器方法,如果访问的是 jsp、html、css、image 或者 js 是不会进行拦截的在 url-pattern 中配置了/*之后,可以对所有要访问的资源过滤
  1. 控制器
@Controller
@RequestMapping("/user")
public class UserController  {
    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        System.out.println("testInterceptor执行了。。。");
        return "success";
    }
}
  1. 拦截器
public class MyInterceptor_1 implements HandlerInterceptor {
    /**
     * 预处理,controller方法执行前
     * return true放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor_1执行了。。。前1111");
        request.getSession().invalidate();
        request.getSession().removeAttribute("");
        //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

  	//后处理方法,controller执行之后,success.jsp执行前
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor_1执行了。。。后1111");
        //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    //success.jsp页面执行后,该方法执行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor_1执行了。。。最后1111");
    }
}
  1. 配置拦截器
<mvc:interceptors>
    <!--配置拦截器-->
    <mvc:interceptor>
        <!--需要拦截的具体的方法-->
        <mvc:mapping path="/user/*"/>
        <!-- 不要拦截的方法<mvc:exclude-mapping path=""/>-->
        <!--配置拦截器对象-->
        <bean class="com.yang.interceptor.MyInterceptor_1"/>
    </mvc:interceptor>
</mvc:interceptors>
  1. 运行结果
MyInterceptor_1执行了。。。前1111
testInterceptor执行了。。。
MyInterceptor_1执行了。。。后1111
success.jsp执行了。。。
MyInterceptor_1执行了。。。最后1111
MyInterceptor_1执行了。。。前1111
MyInterceptor_2执行了。。。前2222
testInterceptor执行了。。。
MyInterceptor_2执行了。。。后2222
MyInterceptor_1执行了。。。后1111
success.jsp执行了。。。
MyInterceptor_2执行了。。。最后2222
MyInterceptor_1执行了。。。最后1111

1.11 相关注解

11.1 RequestParam

@RequestMapping("/useRequestParam") 
public String useRequestParam(@RequestParam("name")String username,       	                           @RequestParam(value="age",required=false)Integer age){ 
    System.out.println(username+","+age);  
    return "success"; 
} 
/***************************************************************************/
<a href="springmvc/useRequestParam?name=test">requestParam 注解</a> 
    
//请求参数中没有配置age,但是由于配置了require为false,因此程序正常执行,没有报错。

11.2 RequestBody

11.3 PathVaribale

@RequestMapping("/usePathVariable/{id}") 
public String usePathVariable(@PathVariable("id") Integer id){  			      		
    System.out.println(id);  
    return "success"; 
} 
/***************************************************************************/
<a href="springmvc/usePathVariable/100">pathVariable 注解</a> 
    
//运行结果为100

11.4 RequestHeader

11.5 CookieValue

11.6 ModelAttribute

@ModelAttribute  
public void showModel(User user) {   
    System.out.println("执行了 showModel 方法"+user.getUsername());  
} 
   /*接收请求的方法*/  
@RequestMapping("/testModelAttribute")  
public String testModelAttribute(User user) {   
    System.out.println("执行了控制器的方法"+user.getUsername());   
    return "success";  
}
/****************************************************************************/
<a href="springmvc/testModelAttribute?username=test">测试 modelattribute</a> 
    
运行结果:
    执行了showModel方法test
    执行了控制器的方法test

11.7 SessionAttributes

//类上添加注释@SessionAttributes(value={"msg"})
//作用等于把msg存入到session域对象中

@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
    System.out.println("testSessionAttributes...");
    //底层会储存到request域对象中
    model.addAttribute("msg","成功!");
    return "success";
}
@RequestMapping("/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
	System.out.println("getSessionAttributes...");
    String msg = (String)modelMap.get("msg");	//取出session域中的msg
    System.out.println(msg);
    return "success";
}
@RequestMapping("/delSessionAttributes")
public String delSessionAttributes(SessionStatus status){
	System.out.println("delSessionAttributes...");
    status.setComplete();		//清除session域参数
    return "success";
}

WebClient 了解、使用!

如果这篇文章对你有帮助,可以通过
支付宝
支付宝
微信
微信
请我喝杯 Coffee ☕


上一篇
从 0 开始的 MyBatis 3.x 学习
下一篇
SpringBoot原理