SpringMVC进阶

异步请求

多个参数,使用@RequestBody 应该如何 获取参数?

该种方法不能通过多参数获取请求体。只能通过POJO的形式接收。

发送AJAX异步请求

要求:除String类型外。前段要以JSON格式的字符串进行传参

适用于 普通、POJO、集合类型

响应:@ResponseBody 将return后的参数以字符串格式用JSON的三方进行转换后返回

请求:@RequestBody 将异步提交数据组织成标准请求格式,并赋值给形参

注意:

​ 1.在MVC中 每一层都要使用对应的注解 不可使用统一的Component,会导致无效化

​ 2.有了@RequestBody,那么就只允许异步请求注入数据,否则报错。

​ 3.如果使用的ajax,那么必须指定 contentType:“application/(text)或(json)”,基本类型-text,POJO-json

<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>

<a href="javascript:void(0);" id="testAjax">访问springmvc后台controller</a><br/>
<a href="javascript:void(0);" id="testAjaxPojo">访问springmvc后台controller,传递Json格式POJO</a><br/>
<a href="javascript:void(0);" id="testAjaxList">访问springmvc后台controller,传递Json格式List</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnString">访问springmvc后台controller,返回字符串数据</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnJson">访问springmvc后台controller,返回Json数据</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnJsonList">访问springmvc后台controller,返回Json数组数据</a><br/>
<br/>
<a href="javascript:void(0);" id="testCross">跨域访问</a><br/>

<script type="text/javascript" src="/js/jquery-3.3.1.min.js"></script>

<script type="text/javascript">
    <%--基本数据,异步请求--%>
    
    $(function () {
        $("#testAjax").click(function () {
            $.ajax({
                type:"POST",
                url:"ajaxTestString1",
                data:'[{msg="哇"}]', //虽然是以json格式发送,但是由于是基本类型接收,所以后端还是会原样输出
                //响应正文类型
                // dataType:"text",     //默认text,可以不指定
                //请求正文的MIME类型
                contentType:"application/text", //使用@RequestBody 注解,必须指定格式。不指定显示null
                success:function (data) {
                   console.log(data)
                },
            })
        })
    });

    <%--JSON对象,异步请求--%>
        // 为id="testAjaxPojo"的组件绑定点击事件
        $("#testAjaxPojo").click(function(){
            $.ajax({
               type:"POST",
               url:"ajaxTest2",
               data:'{"name":"王豆豆","age":23}',  //使用MVC传递的JSON必须加''包围
               // data:'{"ll":"王豆豆","a":23}',
                //响应正文类型
                // dataType:"text",     //响应类型可以不写,默认字符串格式响应回来
                //请求正文的MIME类型
                contentType:"application/json",     //并且要设置请求的正文类型 ,否则报错或不正常显示
               success:function (data) {
                   console.log(data)   //返回的是一个字符串
               }
            });
        });

    <%--JSON集合,异步请求--%>
    //     //为id="testAjaxList"的组件绑定点击事件
        $("#testAjaxList").click(function(){
            $.ajax({
               type:"POST",
               url:"ajaxTest3",
               data:'[{"name":"王豆豆","age":23},{"name":"王豆","age":33}]',
               contentType:"application/json",
                success:function (data) {
                    console.log(data)   //返回的是一个字符串
                }
            });
        });

         <%--不传递数据,异步请求,接收字符串--%>
        //为id="testAjaxReturnString"的组件绑定点击事件
        $("#testAjaxReturnString").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
                url:"ajaxTest4",
               //回调函数
               success:function(data){
                    //打印返回结果
                    console.log(data);
               }
            });
        });

    <%--不传递数据,异步请求,接收对象--%>
    //     //为id="testAjaxReturnJson"的组件绑定点击事件
        $("#testAjaxReturnJson").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"ajaxTest5",
               //回调函数
               success:function(data){
                    alert(data);
                    alert(data['name']+" ,  "+data['age']);
               }
            });
        });

    <%--不传递数据,异步请求,接收集合--%>
    //     //为id="testAjaxReturnJsonList"的组件绑定点击事件
        $("#testAjaxReturnJsonList").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"ajaxTest6",
               //回调函数
               success:function(data){
                    alert(data);
                    alert(data.length);
                    alert(data[0]["name"]);
                    alert(data[1]["age"]);
               }
            });
        });

        //跨域请求
        //为id="testCross"的组件绑定点击事件
        $("#testCross").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"http://www.jock.com/cross",
               //回调函数
               success:function(data){
                   alert("跨域调用信息反馈:"+data['name']+" ,  "+data['age']);
               }
            });
        });
</script>

注意:

    @RequestMapping("/ajaxTest1")
    @ResponseBody   //加上表示返回的是json字符串
    public String ajaxTest1( @RequestBody String msg){
        								//不写@RequestBody在使用异步传递基本类型的时候不能进行注入 会为null
                                           //写了@RequestBody,只能在post方法中使用,且传什么接受什么(原样输出)
        								//不写@RequestBody在使用post传递基本类型的时候 多参数格式用&拼接
   System.out.println("测试方法执行..."+msg);//不写@RequestBody在使用get传递基本类型的时候 只要名字一致就可以进行注入
//        String a = null;
//        a.toString();   		 //此处出现异常,所以会直接跳转到异常类中进行响应。
        return "success.jsp";    //异步的方式就会返回该页面的内容(含标签)
        return "成功";            //添加响应注解且非异步请求,又没有跳转页面。那么就会直接在访问页面输出该返回内容
    }							 //添加响应注解且异步请求,返回给回调函数
								 //返回字符串目前都会乱码,因为没有设置响应的解码操作。后期使用的是Json对象回传,故忽略。

请求地址不需要加/ 框架通过上下文自动匹配(经验证。加了也不会出现找不到的情况)

接收异步请求参数

响应:被@ResponseBody注解定义后, 那么返回什么前端就解析什么。为被注解定义,那么必定返回页面,否则404等错误

提前知道

​ 1. @ResponseBody响应注解也可以加到方法返回值类型之前,效果一致。

​ 2.由于前端的数据都是String类型,所以后端必须都已String类型进行接收,否则报错!如果要其他基本类型,转型。

​ 3.对POJO进行映射。POJO中没有该属性名–null

​ 名字不对等–null

​ 未写请求注解–null

​ 4.确定是否指定contentType,主要依据是否传递数据到后端

接收基本数据类型

基本原则:后端不使用注解,那么前端就不使用 contentType:"application/text"

​ 注意事项:

​ 1.ajax指定post方式进行传输

​ 2.多参数的数据传输类型以&进行连接

​ 3.前端有contentType,后端没有注解,结果未null

​ 没有 ,有 ,结果不解析编码字符 %5B%7Bmsg=s%E6%98%AF%

1.多参数

情况一:基本类型不使用@RequestBody,并且需要是字符串类型

前端jsp

//多参数的基本类型异步请求
$(function () {
    $("#testAjax").click(function () {
        $.ajax({
            type:"POST",						  //指定访问方式
            url:"ajaxTest1",
            data:'msg=王豆豆&age=27&...',     		//按照get地址栏的方式进行传递
            success:function (data) {           
               console.log(data)
            },
        })
    })
});

后端

//多参数基本类型调用方法
@RequestMapping("/ajaxTest1")
@ResponseBody   //加上表示返回的是json字符串
public String ajaxTest1(String msg,String age){
     //不写@RequestBody在使用异步请求传递基本类型的时候 只要名字一致就可以进行注入
    System.out.println("测试方法执行..."+msg+"...."+age);  
    return "成功";    //异步的方式就会返回该页面的内容
                      //添加注解。非异步,又没有跳转页面。那么就会直接在访问页面输出该返回内容
}

情况二:使用@RequestBody是对引用POJO类型进行定义

2.单参数

后端不使用注解,那么前端就不使用 contentType:"application/text"

​ 如果后端未使用请求注解,前端使用则会出现如下情况: 编码不会进行转码操作。

//方法的参数进行打印后的显示结果
测试方法执行...%5B%7Bmsg=s%E6%98%AF%2Cnum%3D7%7D%5D....

接收POJO类型

​ 1.后端使用POJO接收,前端如果要传递参数必须指定 contentType:“application/json” 格式

​ 2.传递的数据必须是字符串形式的JSON

​ 3.如下的案例都是把数据写死,如果要用动态数据。

​ 提供方案:提前定义好动态的JSON变量进行存储。在异步中 data: 变量.stringfy()解析为字符串

前端

<%--JSON对象,异步请求--%>
    // 为id="testAjaxPojo"的组件绑定点击事件
    $("#testAjaxPojo").click(function(){
        $.ajax({
           type:"POST",
           url:"ajaxTest2",
           data:'{"name":"王豆豆","age":23}',  //使用MVC传递的JSON必须加''包围
           // data:'{"ll":"王豆豆","a":23}',   //后端POJO属性不一致,不进行封装
            //响应正文类型
            // dataType:"text",     //响应类型可以不写,默认字符串格式响应回来
            //请求正文的MIME类型
            contentType:"application/json",     //并且要设置请求的正文类型 ,否则报错或不正常显示
           success:function (data) {
               console.log(data)   //返回的是一个字符串
           }
        });
    });

<%--JSON集合,异步请求--%>
//     //为id="testAjaxList"的组件绑定点击事件
    $("#testAjaxList").click(function(){
        $.ajax({
           type:"POST",
           url:"ajaxTest3",
           data:'[{"name":"王豆豆","age":23},{"name":"王豆","age":33}]',
           contentType:"application/json",
            success:function (data) {
                console.log(data)   //返回的是一个字符串
            }
        });
    });

     <%--不传递数据,异步请求,接收字符串--%>
    //为id="testAjaxReturnString"的组件绑定点击事件
    $("#testAjaxReturnString").click(function(){
        //发送异步调用
        $.ajax({
           type:"POST",
            url:"ajaxTest4",
           //回调函数
           success:function(data){  //后端传递的是字符串
                //打印返回结果
                console.log(data);
           }
        });
    });

<%--不传递数据,异步请求,接收对象--%>
//     //为id="testAjaxReturnJson"的组件绑定点击事件
    $("#testAjaxReturnJson").click(function(){
        //发送异步调用
        $.ajax({
           type:"POST",
           url:"ajaxTest5",
           //回调函数
           success:function(data){   //后端传递的是UserPOJO的对象
                alert(data);
                alert(data['name']+" ,  "+data['age']);
           }
        });
    });

<%--不传递数据,异步请求,接收集合--%>
//     //为id="testAjaxReturnJsonList"的组件绑定点击事件
    $("#testAjaxReturnJsonList").click(function(){
        //发送异步调用
        $.ajax({
           type:"POST",
           url:"ajaxTest6",
           //回调函数
           success:function(data){  //后端传递的是UserPOJO的集合
                alert(data);
                alert(data.length);
                alert(data[0]["name"]);
                alert(data[1]["age"]);
           }
        });
    });

后端

//传递字符串json对象
    @RequestMapping("/ajaxTest2")
    //如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
    //注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
    public String  ajaxTest2(@RequestBody User user){  //不写@RequestBody在给POJO赋值的时候不进行赋值。
        System.out.println("controller pojo :"+user);
        return "page.jsp";
    }

    //传递字符串jso数组
    @RequestMapping("/ajaxTest3")
    //如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中
    public String  ajaxListToController(@RequestBody List<User> userList){
        System.out.println("controller list :"+userList);
        return "page.jsp";
    }

    //不传递信息,返回字符串
    //使用注解@ResponseBody可以将返回的页面不进行解析,直接返回字符串,该注解可以添加到方法上方或返回值前面
    @RequestMapping("/ajaxTest4")
//    @ResponseBody
    public @ResponseBody String ajaxReturnString(){
        System.out.println("controller return string ...");
        return "page.jsp";
    }

    //不传递信息,返回POJO
    @RequestMapping("/ajaxTest5")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的POJO对象转成json格式数据
    public User ajaxReturnJson(){
        System.out.println("controller return json pojo...");
        User user = new User();
        user.setName("Jockme");
        user.setAge(39);
        return user;
    }

    //不传递数据,返回集合
    @RequestMapping("/ajaxTest6")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
    public List ajaxReturnJsonList(){
        System.out.println("controller return json list...");
        User user1 = new User();
        user1.setName("Tom");
        user1.setAge(3);

        User user2 = new User();
        user2.setName("Jerry");
        user2.setAge(5);

        ArrayList al = new ArrayList();
        al.add(user1);
        al.add(user2);

        return al;
    }

跨域访问

定义:不同服务器通过域名A 访问域名B下的资源的时候称为跨域访问。同服务器,两个域名,也叫做跨域

​ 协议、 ip地址 、端口号 、域名,只要有一个不同都叫做跨域访问。

跨域问题实质产生的原因是因为浏览器导致的。

后端代码直接调用不会出现跨域问题 new URL(”地址“)

@CrossOrgin 可以用在方法或者类上 指定某个方法或者全部方法

使用于: A项目存在某个模块功能 B项目也需要使用

​ 可以实现不复制,直接跨域访问。

//跨域访问
@RequestMapping("/cross")
@ResponseBody
//使用@CrossOrigin开启跨域访问
//标注在处理器方法上方表示该方法支持跨域访问
//标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问
@CrossOrigin //定义注解
public User cross(HttpServletRequest request){
    System.out.println("controller cross..."+request.getRequestURL());
    User user = new User();
    user.setName("Jockme");
    user.setAge(39);
    return user;
}

拦截器

拦截器的完成操作的ex异常对象。可以在完成中处理异常。那么异常处理类拿来干嘛?

异常处理是全局处理,可以对全局的异常做出判断。拦截器异常范围较小,主要针对被拦截的这些类的异常作出处理。

概念

​ 拦截器本质是一个AOP,功能是对所有经过MVC访问的请求进行拦截再判断的操作。可以在执行代码前后分别进行拦截,以达到统一处理逻辑的目的。

在这里插入图片描述

拦截器与过滤器的区别

​ 拦截器只拦截Spring所管理的BEAN

​ 过滤器是拦截所有经过tomcat的请求和响应

在这里插入图片描述

自定义拦截器

拦截器可以自定义多个

步骤:

0.实现handlerIntercepter接口 重写方法(默认AOP环绕类型)

1.拦截器类(通知)

​ 前置返回 false ---- 不向下放行 前面有完成或后置方法就执行,没有就退出拦截链

​ 前置返回 true ----执行处理器-- 后置–完成后

注意: 如果在后置或者完成中执行 输出流类型的操作会引起页面跳转时乱码问题或者导致IOC抛出异常。

package com.itheima.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//自定义拦截器需要实现HandleInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
    //处理器运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("前置运行----a1");
        //返回值为false将拦截原始处理器的运行
        //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
        return true;
    }

    //处理器运行之后执行
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("后置运行----b1");
                //返回
//        response.getWriter().write("ok");    跳转页面时出现乱码情况
    }

    //所有拦截器的后置执行全部结束后,执行该操作
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("完成运行----c1");
                //返回
//        response.getWriter().write("ok");       处理器执行返回操作时会导致抛出异常
    }

    //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
    //如果preHandle返回值为false,三个方法仅运行preHandle
}

测试类

    @RequestMapping("/show")
//    @ResponseBody 		    //不能执行响应体
    public String showSTH(){
        System.out.println("第一个MVC,HELLOWORLD!!");
        return "success.jsp";   //执行完成跳转 页面	
    }

2.配置拦截器(切点)

​ 1.配置拦截路径

​ 2.配置拦截器

<!--配置拦截器-->
<mvc:interceptors>
    <!--开启具体的拦截器的使用,可以配置多个-->
    <mvc:interceptor>
        <!--设置拦截器的拦截路径,支持*通配-->
        <!--/**         表示拦截所有映射-->		  比如@RequestMapping("show")
        <!--/*          表示拦截所有/开头的映射--> 比如@RequestMapping("/show") 注意:可以直接访问show也可以/show访问
        <!--/user/*     表示拦截所有/user/开头的映射-->
        <!--/user/add*  表示拦截所有/user/开头,且具体映射名称以add开头的映射-->
        <!--/user/*All  表示拦截所有/user/开头,且具体映射名称以All结尾的映射-->
        <!-- <mvc:mapping path="/*"/>-->
        <mvc:mapping path="/**"/>
        <mvc:mapping path="/show"/>
        <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的-->
        <!--<mvc:exclude-mapping path="/b*"/>-->
        <!--指定具体的拦截器类-->
        <bean class="com.springMVC02.interceptor.MyInterceptor"/>
    </mvc:interceptor>

</mvc:interceptors>

拦截器参数

前置方法

​ handler : 被调用处的处理器方法对象,通过反射获取的Method对象,是该对象的包装类。

​ 意思是可以对方法通过反射的形式进行逻辑操作

​ 打印结果:

public java.lang.String com.springmvc.controller.controlDemo.showSTH()
后置方法

modelandview 带数据跳转页面时使用的对象 可以在此处判断该结果对象的参数,满足放行,不满足强制跳转到其他页面等操作。

​ 注意,如果是使用的异步请求,则不会存在该对象。而是使用响应回传JSON字符串。

完成方法

ex :异常处理。有点类似于异常拦截。可以在该层对处理进行统一处理。

统一参数

请求req,响应resp 每一层都有,可以在对应层对该请求或者响应调用API做出相应逻辑判断。

拦截器的工作流程

多个拦截器配置,拦截器与上述一致。

<mvc:interceptors>
    <!--开启具体的拦截器的使用,可以配置多个-->
    <mvc:interceptor>
        <!--设置拦截器的拦截路径,支持*通配-->
        <!--/**         表示拦截所有映射-->
        <!--/*          表示拦截所有/开头的映射-->
        <!--/user/*     表示拦截所有/user/开头的映射-->
        <!--/user/add*  表示拦截所有/user/开头,且具体映射名称以add开头的映射-->
        <!--/user/*All  表示拦截所有/user/开头,且具体映射名称以All结尾的映射-->
        <!--<mvc:mapping path="/*"/>-->
        <!--<mvc:mapping path="/**"/>-->
        <mvc:mapping path="/show"/>
        <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的-->
        <!--<mvc:exclude-mapping path="/b*"/>-->
        <!--指定具体的拦截器类-->
        <bean class="com.springMVC02.interceptor.MyInterceptor"/>
    </mvc:interceptor>

    <!--配置多个拦截器,配置顺序即为最终运行顺序-->

    <!--配置第二个拦截器-->
    <mvc:interceptor>
        <mvc:mapping path="/*"/>
        <bean class="com.springMVC02.interceptor.MyInterceptor2"/>
    </mvc:interceptor>

    <!--配置第三个拦截器-->
    <mvc:interceptor>
        <mvc:mapping path="/show"/>
        <bean class="com.springMVC02.interceptor.MyInterceptor3"/>
    </mvc:interceptor>

</mvc:interceptors>

1.配置顺序就是运行顺序

2.进入/出去的顺序 123 – 321 完成时也时321 但是是在所有后置结束后开始执行

12 可以正常进入 如果3 不可进入 那么后置21 完成后 完成21

​ 注意 只要2遇到false 由于不执行后面,那么从2开始后面的都不会执行,只执行1的完成和后置

这是我的前置...1        //先把全部的前置执行
这是我的前置...2
这是我的前置...3
第一个MVC,HELLOWORLD!!
这是我的后置...3		 //由于全是true,所以会放行所以后置和完成
这是我的后置...2
这是我的后置...1
这是我的完成后...3		//当全部后置完成,再执行完成
这是我的完成后...2
这是我的完成后...1    
    
-----------------以下是对拦截器3返回false后的显示结果--------------------
这是我的前置...1
这是我的前置...2
这是我的前置...3
                  //未执行处理器,即便通过拦截器1,2  因为拦截器3进行了拦截。最终只执行完成2,1
这是我的完成后...2
这是我的完成后...1

在这里插入图片描述

责任链模式

责任链模式实际上是一种设计模式

特征是:沿着预先本设定好的一条责任链顺序执行,每个节点都有自己独立的功能。但又由于责任链机制,所以要把重要的节点放在前面执行,以免被false掉。

底层代码是一个拦截器的数组

每个按顺序进行循环判断 如果碰到为false的拦截器就调用当前的完成方法 然后结束

好处

​ 独立性:只关注自己本节点的任务。

​ 隔离性:不会对上一节点或者下一节点进行干预,只要到达自己本节点就干活。

​ 灵活性:可以随时对拦截器进行增删改的操作。

​ 解耦 :把整个链始终至于解耦的状态。

坏处

过长时,会影响效率低下。

可能在节点的引用由于if判断而出现循环的情况,出现死循环导致系统崩溃

异常处理

可以对Spring管理的类的方法都进行管理,只要出现异常就会进入到设置好的这个异常类中

普通类异常

步骤:

​ 1.自定义异常类 实现接口 HandlerExcetionResolver

​ 2.重写异常拦截器方法

​ 3.把该类存入IOC中

​ 4.使用ex的变量做异常分类判断表示逻辑

​ 5.使用ModelAndView 设置返回

//@Component   将该类存入IOC
public class ExceptionResolver implements HandlerExceptionResolver {  //实现接口,重写方法
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,		//这是一个拦截器,所有参数与完成拦截器一致。
                                         Exception ex) {		
        
        System.out.println("my exception is running ...."+ex); //测试ex异常类型
        
        ModelAndView modelAndView = new ModelAndView();	 //创建返回结果对象(跳转页面时使用)
        
        //由于异常太多不一一列举,此处只指定几个做演示
        if( ex instanceof NullPointerException){	
            modelAndView.addObject("msg","空指针异常");
        }else if ( ex instanceof  ArithmeticException){
            modelAndView.addObject("msg","算数运算异常");
        }else{
            modelAndView.addObject("msg","未知的异常");
        }
        
        modelAndView.setViewName("error.jsp");  //由于只要有异常就一定会被捕获到进入异常拦截器,所以必定要跳转到异常页面
        return modelAndView; //返回该结果  固定格式
    }
}

注解异常

步骤:

​ 1.定义异常类

​ 2.注解 @ControllerAdvice AOP的机制

​ 3.定义方法 参数列表为Exception e 上方注解 @ExceptionHandler(异常.class)

​ 由于是一个方法要进行返回字符串,所以也要像正常返回字符串一样使用其他的注解进行回显 如:@ResponseBody

​ 最终是返回给前端,让其做出相应的显示。

@Component
@ControllerAdvice  //使用该异常类作为拦截异常,声明该类是一个Controller的通知类,声明后该类就会被加载成异常处理器
public class AnnotationException  {

    //定义异常方法
    @ExceptionHandler
    @ResponseBody
    public Result showException(Exception e){
        Result result = new Result();
        result.setMsg("空指针异常");    //需要把该对象放入容器中
        result.setStatus(false);
        e.printStackTrace();            //打印异常信息
        return result;   //要返回对象就要写上@ResponseBody注解,否则异步时为字符串
    }
}

区别

注解 : 在控制器生成之后就进行加载,加载得早

接口类 :加载得晚,部分异常无法拦截

结论:统一使用注解的异常处理方式

企业级开发异常处理

​ 在对应有可能出现异常的地方都使用try。。catch包装,在catch中new 一个异常 ,定义该异常的名字。抛出

​ 在异常类中统一按照合适的信息显示给用户

​ 在企业级开发中,不可能将所有的异常都进行分类,必定是由我们自己对类进行定义。对不同的异常在catch中new一个自定义的异常信息往上抛。

在这里插入图片描述

自定义异常

​ 作用: 在企业级开发中,不可能将所有的异常都进行分类,必定是由我们自己对类进行自定义。

​ 对不同的异常在catch中new一个自定义的异常信息。不做任何处理,最终使到达处理类中。

业务异常类
package com.itheima.exception;
//自定义异常继承RuntimeException,覆盖父类所有的构造方法
public class BusinessException extends RuntimeException {
    public BusinessException() {
    }

    public BusinessException(String message) {
        super(message);				//有参构造器,要求创建时必须写出异常信息
    }

    public BusinessException(String message, Throwable cause) {
        super(message, cause);		//往上抛异常时,要携带真正的异常信息给运维人员看
    }

    public BusinessException(Throwable cause) {
        super(cause);	
    }

    public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
系统异常类
package com.itheima.exception;
//自定义异常继承RuntimeException,覆盖父类所有的构造方法
public class SystemException extends RuntimeException {
    public SystemException() {
    }

    public SystemException(String message) {//同上
        super(message);
    }

    public SystemException(String message, Throwable cause) {
        super(message, cause);		//同上
    }

    public SystemException(Throwable cause) {
        super(cause);
    }

    public SystemException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
异常处理类
package com.itheima.exception;

import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@Component
@ControllerAdvice
public class ProjectExceptionAdvice {

    @ExceptionHandler(BusinessException.class)   //接收业务异常
    public String doBusinessException(Exception ex, Model m){
        //使用参数Model将要保存的数据传递到页面上,功能等同于ModelAndView
        //业务异常出现的消息要发送给用户查看
        m.addAttribute("msg",ex.getMessage());
        return "error.jsp";
    }

    @ExceptionHandler(SystemException.class)	//接收系统异常
    public String doSystemException(Exception ex, Model m){
        //系统异常出现的消息不要发送给用户查看,发送统一的信息给用户看
        m.addAttribute("msg","服务器出现问题,请联系管理员!");
        //实际的问题现象应该传递给redis服务器,运维人员通过后台系统查看
        //实际的问题显现更应该传递给redis服务器,运维人员通过后台系统查看
        return "error.jsp";
    }

    @ExceptionHandler(Exception.class)		//处理其他异常,给运维人员看
    public String doException(Exception ex, Model m){
        m.addAttribute("msg",ex.getMessage());
        //将ex对象保存起来
        return "error.jsp";
    }

}

测试类
public class UserServlceImpl {
    public void save(){
        //业务层中如果出现了异常,就对出现异常的代码进行try...catch...处理
        //在catch中将出现的异常包装成自定义异常,同时务必将当前异常对象传入自定义异常,避免真正的异常信息消失
        try {
            throw new SQLException();  //模拟异常
        } catch (SQLException e) {
            throw new SystemException("数据库连接超时!",e);   //捕获后重新包装为系统异常,存入真实错误信息,最终到达异常处理类
        }
    }
}

实用技术

文件上传下载

​ Spring把文件上传的各个操作封装为了一个接口

步骤:

1.文件上传下载Spring坐标

<!--文件上传下载-->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.4</version>
</dependency>

2.在spring配置文件中要对IOC配置上传的对象(id有固定值,不能动)

<!--配置文件上传处理器-->
	//id不可变												//必须使用该类
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="1024000000"/>	//设置上传文件的最大内存 三方提供上限为10M
</bean>

3.前端的name 与后端方法的形参一致

<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>
			//指定访问路径		//指定方式			//指定为上传格式
<form action="/fileupload" method="post" enctype="multipart/form-data">  
    
    <%--文件上传表单的name属性值一定要与controller处理器中方法的参数对应,否则无法实现文件上传--%>
    上传LOGO:<input type="file" name="fileImag"/><br/>  
    上传照片:<input type="file" name="file1"/><br/>
    上传任意文件:<input type="file" name="file2"/><br/>
    <input type="submit" value="上传"/>
    
</form>

4.调用transferto(new File(“指定保存位置”))方法

注意: 表单中要设置上传的专用属性enctype

//@Component
@Controller   //只要是由前端直接访问的类 都必须是Controller
public class UploadFile {
    //定义上传方法
    @RequestMapping("/fileupload")
    						//参数类必须使该类
    public void saveUploadFile(MultipartFile fileImag) throws IOException {
        fileImag.transferTo(new File("abc.png"));  //存到默认根路径下
    }
}
文件上传所需要解决的问题

在这里插入图片描述

restful风格编程

restful是一套规范。简化get的使用方式

提交的方法有十几种,这里只列举四种

get 查询

post 保存

put 更新

delete 删除

/user/{id} 路径 不指定提交类型则全部支持

/user/{id} ,method=RequestMethod.提交方法 使用该种方式,那么就不能使用其他类型的提交方式

使用@PathVariable 从路径中取变量 参数名与路径中的名字一样

如果是跳转页面,默认返回的页面是以访问路径作为跳转的虚拟路径

合并注解@Controller @ResponesBody

@RestController

配置步骤:

导包

postman表单校验

是一款工具,有了该工具就可以不再使用浏览器进行访问服务器

在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值