Controller参数总结

目录

 一、参数接受

1.post/get

1.是什么:是HTTP协议中的两种发送请求的方法。

2.两者的区别

(1)简单来说GET请求会把参数包含在URL中,POST通过request body传递参数。(把get和post比作运输的车,当使用get时给汽车贴上GET的标签(设置method为GET),而且要求把传送的数据放在车顶上(url中)以方便记录。如果使用post,就要在车上贴上POST的标签,并把货物放在车厢里。)

(2)GET在浏览器回退时是无害的,而POST会再次提交请求。

(3)GET产生的URL地址可以被Bookmark,而POST不可以。

(4)GET请求会被浏览器主动cache,而POST不会,除非手动设置。

(5)GET请求只能进行url编码,而POST支持多种编码方式。

(6)GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

(7)GET请求在URL中传送的参数是有长度限制的,而POST么有。

(8)对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

(9)GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

(10)GET参数通过URL传递,POST放在Request body中。

3.补充

1.GET :请求指定的页面信息,并返回实体主体。

2.POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。

3.PUT:从客户端向服务器传送的数据取代指定的文档的内容。

4.DELETE:请求服务器删除指定的页面。

4.请求参数注解

1.@RequestParam

(1)注解@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中。

(2)RequestParam可以接受简单类型的属性,也可以接受对象类型。

(3)@RequestParam有三个配置参数:
        value:请求中传入参数的名称,如果不设置后台接口的value值,则会默认为该变量名。比 如第一个参数如果不设置value=“page”,则前端传入的参数名必须为pageNum,否则在后台接口中pageNum将接收不到对应的数据。

        required:该参数是否为必传项。默认是true,表示请求中一定要传入对应的参数,否则会报404错误,如果设置为false时,当请求中没有此参数,将会默认为null,而对于基本数据类型的变量,则必须有值,这时会抛出空指针异常。如果允许空值,则接口中变量需要使用包装类来声明。

        defaultValue:参数的默认值,如果请求中没有同名的参数时,该变量默认为此值。

(4)@RequestParam用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容,Content-Type默认为该属性。

(5)@RequestParam也可用于其它类型的请求,例如:POST、DELETE等请求。

用例

1.获取url参数值,默认方式,需要方法参数名称和url参数保持一致

 @GetMapping("/param1")
        public String sayHello(@RequestParam Integer id){
            return "id:"+id;

    }

浏览器地址输入:localhost:8080/param1?id=1000 

 

2. url中有多个参数时

    @GetMapping("/param2")
    public String param2(@RequestParam Integer id,@RequestParam String name){
        return "id:"+id+ " name:"+name;
    }

浏览器地址输入:localhost:8080/param2?id=500&name=娃哈哈 

 3.获取url参数值,执行参数名称方式

    @GetMapping("/param3")
        public String param3(@RequestParam("userId") Integer id){
            return "id:"+id;
        }

 浏览器地址输入:localhost:8080/param3?userId=9999   

注意:不输入userId则会报错  必须与参数名一致

4.不输入id时,使用默认值 

    @GetMapping("/param4")
    //required=false 表示url中可以无id参数,此时就使用默认参数
    public String param4(@RequestParam(value="id",required = false,defaultValue = "1") Integer id){
        return "id:"+id;
    }

 在浏览器地址不输入值,则会使用默认值,例:localhost:8080/param4

2.@RequestBody

(1)@RequestBody 主要用来接收前端传递给后端的 json 格式的数据的(请求体中的数据的),有一个属性 required,表示参数是否必须要传,默认为 true.

(2)GET 方式无请求体,所以 @RequestBody 接收数据时,前端必须是 POST 方式进行提交,然后给页面的数据默认也是 json

(3)同一个方法中, @RequestBody  与 @RequestParam()  可以同时使用,前者最多只能有一个,后者可以有多个,

(4)@RequestBody 接收的是请求体里面的数据, @RequestParam  接收的是 key-value  里面的参数。

注意:

如果后端参数是一个对象,且该参数前是以@RequestBody修饰的,那么前端传递json参数时,必须满足以下要求:

(1)后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为), 实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。
(2)json字符串中,如果value为””的话,后端对应属性如果是String类型的,那么接受到的就是””,如果是后端属性的类型是Integer、Double等类型,那么接收到的就是null。
(3)json字符串中,如果value为null的话,后端对应收到的就是null。
(4)如果某个参数没有value的话,在传json字符串给后端时,要么干脆就不把该字段写到json字符串中;要么写value时, 必须有值,null 或””都行。
 

用例

json格式数据:

{
    "name":"蛋炒饭",
    "price":1000,
    "code":"",
    "image":"da9e1c70-fc32-4781-9510-a1c4ccd2ff59.jpg",
    "description":"好吃又实惠",
    "status":1,
    "categoryId":"1397844357980663809",
    //"categoryName":"豫菜",
    "flavors":[
        {
            "name":"辣度",
            "value":"[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]"
        },
        {
            "name":"忌口",
            "value":"[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]"
        }
    ]
}

具体使用 只要前台传过来的是json数据,必须加这个注解,否则会接收不到数据

    @PostMapping("/addUser")
    public void addUser(@RequestBody User user){
        System.out.println(user);

    }

  

3.@PathVariable

(1)@PathVariable用于接收路径参数,使用{参数名称}描述路径参数,这个注解可以实现url请求参数中的占位符到目标方法中参数的映射。

(2)通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器(controller)处理方法的形参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的形参中。

(3)String value:可指定占位符 { } 中的参数名,若只指定value这一个属性可省略属性名不写,若占位符中的参数名和处理方法中的参数名相同可省略此属性。
(4)String name:等价与value,和value无本质上的差异,两个属性指定其一即可。
(5)boolean required:是否必需,默认为 true,即 请求中必须包含该参数,如果没有包含,将会抛出异常(可选配置)
 

具体使用:

(1)如果页面传入的参数(请求链接上)和类中接收参数不一致,需要使用注解value属性写上页面传入的参数名。

    @RequestMapping(value="/user/{name}")
    public String username(@PathVariable(value="name") String username) {
        return username;
    }

 在浏览器端输入地址:localhost:8080/user/name=胡歌

(2)如果页面传入的参数(请求链接上)和类中接收参数一致,value属性可以不写,但是@PathVariable注解不可省略,否则会导致报错。

    @RequestMapping(value="/user/{name}/{id}")
    public String PathVariable2(@PathVariable String name,String id) {
        return name+","+id;
    }

  在浏览器端输入地址:localhost:8080/user/name=胡歌,id=555

二、表单提交

1.提交方式

form表单提交,表单提交分两种:自动提交(submit) 和 手动提交(button)。

form表单提交又分为:post提交和get提交。

2.常用属性

action 与method是form表单的两个属性: 

(1)action:规定当提交表单时向何处发送表单数据。

(2)method (get/post) :规定用于发送form-data的HTTP方法。(提交表单的方式)

3.form表单提交用例

1.submit提交(默认method=”post”)

(1)在form标签中添加Action(提交的地址)和method(post),且有一个submit按钮(<input stype=“submit”>),通过点击这个按钮提交表单数据。—-type="submit"是将表单提交(即form.submit()方法)作为其onclick后的默认事件。

(2)type="submit"会自动将所具有的name属性html输入的元素(包括input、button、select等标签都作为键值对提交)。

(3)type="submit"submit会有一个跳转,页面会刷新。

   <form action="http://www.baidu.com">
        <input type="text" name="username">
        <input type="text" name="password">
        <input type="submit" value="登录">
    </form>

注意:

1.当点击登录时,向服务器发生的数据是:username=username&password=password。
2.这种默认的提交方式,一般会进行页面的跳转(不成功时跳转到当前页面),而有时我们对弹出框进行数据提交的,希望提交成功则关闭弹出框并刷新页面,失败则提示失败原因,且弹出框不关闭。此时可以采用ajax进行数据提交。

区别:

type = submit 与type = botton的区别

当type = submit时,该点击发生后,就直接启动了form的提交,而type = botton时,只是表明了该标签是一个按钮,当发生点击时,form没有任何的反应。

2.form表单带附件提交

需要shedinform的entype=“multipart/form-data”并且添加<input type=‘file’>,除此之外还需要将表单的提交方法改成post,而且附件只能通过submit方法提交。

<form action="/url.do" enctype="multipart/form-data" method="post">
     <input type="file" name="name"/>
     <input type="submit" value="提交">
</form>

3.带验证提交

3.1 onsubmit提交验证

该提交方式中 input 或者 button 的type还是 submit类型的,但是在form 表元素里面需要加上 οnsubmit=”return check()”。其中 check(),是我们用来做验证的函数,且前面必须加 return,否则无论我们的返回值是什么,表单就都将会提交。

<form action="www.baidu.com" method="post" onsubmit="return check()">
    <input type="text" name="name"/>
    <input type="submit" value="提交"/>
    <button type="submit">提交</button>
</form>

</body>
<script type="text/javascript">
    function check() {
        if(){
            return true;    //return true; 时,表单将提交
        }
        else {
            return false;   //return false; 时,表单不提交
        }
    }
</script>

上述提交的check函数中,我们可以对表单里面的数据进行判断或者验证,当验证结果是我们需要的,我们就可以返回true,将表单提交,如果是错误的,那么我们可以对表单做接下来的一些处理再 return true,或者干脆return false,做到不提交,这样就保证了我们数据的安全性,当数据不需要时,我们就不提交。

3.2  $(“form”).submit()

该提交方式中 input 或者 button 的type则应该是button类型的,因为这样写就是为了做到验证,然后判断是否需要提交,如果写成了submit的话,就是变成无论如何都要提交了,将type=button,然后后给元素添加一个onclick事件,绑定函数,当在函数里面判断后,如果需要提交,则可以添加 $(“form”).submit(); 语句,表示需要提交了,如果不想提交,则将该语句规避就可以了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form表单提交</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<form action="../../Controller/method" method="post">
    <input type="text" name="name"/>
    <input type="button" value="提交" onclick="check()">
    <button type="button" onclick="check()">提交</button>
</form>

</body>
<script type="text/javascript">
    function check() {
        /**
         * 编写验证代码,若不想提交,就可以提前return;达到不提交
         */
        $("form").submit();
    }
</script>
</html>

3.3  jQuery插件:Validation

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form表单提交</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.10.0/jquery.validate.min.js"></script>
</head>
<body>
<form action="../../Controller/method" method="post">
    <input type="text" name="name"/>
    <input type="submit" value="提交">
    <button type="submit">提交</button>
</form>

</body>
<script type="text/javascript">
    $(function () {
        $("form").validate({
        /**
       	 * 只是写一个例子,所以验证并没有给出
       	 */
            submitHandler:function (form){
                /**
                 * 添加我们需要的验证信息
                 * 如果不需要提交,还是直接return就行了,规避form.submit();
                 */
               form.submit();
            }
        });
    });
</script>
</html>

注意:

使用该方法时,我们必须引入jQuery的插件(上述代码已给出),并且我们的 input 或者 button 的type则应该是submit类型的,否则不会响应,所谓的不会响应就是压根就不会执行。submitHandler:function 下面的这个函数因为当表单验证成功并提交时执行,存在此方法时表单只能在此方法内部执行form.submit()才能提交,可理解成它替代了表单的onsubmit方法。但是button在前面已经说过了,它并不是一个提交,而是表明它只是一个按钮而已,所有input 或者 button 的type则应该是submit类型的。

在submitHandler:function 函数的最后如果需要提交,执行的一定是form.submit(),而不是$(“form”).submit();因为后者会造成一个死循环,因为上面解释过了。submitHandler:function 是在表单验证改成并且执行提交时才会执行,而$(“form”).submit();就是表单执行提交,所以每一次都执行提交,然后跳转submitHandler:function ,然后在该函数里面又执行了提交,所以就变成了一个死循环。

4.Ajax提交

当我们需要提交一些数据,且想获取一些返回信息,且不想刷新页面时,就可以利用我们的Ajax的方式提交了。

4.1  Ajax参数说明

4.1.1  contentType

(1)其默认值为application/x-www-form-urlencoded; charset=UTF-8—-即指定窗体数据被编码为名/值对,这是标准的编码格式。(表单默认的提交数据的格式)
(2)对于跨域请求,contentType设置为application/x-www-form-urlencoded, multipart/form-data或 text/plain以外。
(3)text/plain:窗体数据以纯文本形式进行编码,其中不含任何空间或者格式字符。
(4)application/json:窗体数据以json的书韩剧格式来传递([{},{}])。

4.1.2  data

(1)是发送到服务器的数据 ,它被转换成一个查询字符串,如果已经是一个字符串的话则不会转换,查询字符串将被追加到get请求url后面。
(2)以防止这种自动转换,对象必须为”{键:值}”格式。
(3)如果参数是一个数组。jQuery会按照traditional参数的值,将自动转化为一个同名的多址查询字符串。

用例:

<script>
    function onSubmit(){
        var data={
            name:'huangzhizhen',
            score:'100',
            weekDays:[1,2,2,3]
        };
        $.ajax({
            type:"POST",
            url:'//www.baidu.com',
            data:data,
            dataType:'json',
            contentType: 'application/x-www-form-urlencoded',
            success:function(req){
                console.log(req)
            },
            error:function(e){
                console.log(e)
            }
        })
    }
</script>

4.1.3  dataType

说明:从服务器你期望的数据类型,如果没有指定,jQuery将尝试通过MIME类型的响应信息来智能判断。

1)dataType:“xml” —-返回xml文档,可以荣光jQuery处理。
2)dataType:“html“—返回纯文本html文本,包含script标签会插入DOM执行。
3)dataType:”json“—-把响应结果当作JSON执行,并返回一个javascript对象。跨域”json”请求转换为“jsonp”。

4.1.4  data部分的数据是如何组装进请求的

(1)当method为post时:浏览器把form数据封装到http body中,然后发送到server。

(2)当method为get时:则浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=name1&name2=name2…)然后把这个字串append到url后面,用?分割,加载这个新的url。

4.2 Ajax提交方式

4.2.1  表单插件jQuery.form.js 的 $(‘form’).ajaxSubmit({})方式

该方式必须引入jQuery的表单插件,下面的是该表单插件的在线方式
<script src=“https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js”></script>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form表单提交</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.10.0/jquery.validate.min.js"></script>
 $('form').ajaxSubmit({
</head>
<body>
<form action="../../Controller/method" method="post">
    <input type="text" name="name" value="form表单提交"/>
    <input type="button" value="提交" onclick="submitTest()"/>
    <button type="button" onclick="submitTest()">提交</button>
</form>

</body>
<script type="text/javascript">
    function submitTest(){
        $('form').ajaxSubmit({
            url: $("from").attr("action"),
            type: $("from").attr("method"),
            dataType: 'json',
            beforeSubmit: function () {},
            success: function (result) {
                /**
                 * 成功的回调函数
                 */
            },
            error:function(){
                /**
                 * 失败的回调函数
                 */
            },
            clearForm: false,//禁止清楚表单
            resetForm: false //禁止重置表单
        });
    }
</script>
</html>

注意:

这种方式是jQuery的插件Ajax提交,需要注意的是,input 和button的type都必须是button,然后给他们绑定一个事件函数,在函数里写上Ajax的提交,如果不是button而是submit的话,点击一次的按钮将会执行两次的提交,一次是form的自身提交,一次是Ajax的提交,所以type必须为button 。

4.2.2  表单插件jQuery.form.js 的 $(‘form’).ajaxFrom({})方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form表单提交</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.10.0/jquery.validate.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery.form/4.2.1/jquery.form.min.js"></script>
</head>
<body>
<form action="../../Controller/method" method="post">
    <input type="text" name="name" value="form表单提交"/>
    <input type="submit" value="提交" onclick="submitTest()"/>
    <button type="submit" onclick="submitTest()">提交</button>
</form>

</body>
<script type="text/javascript">
    function submitTest(){
        $('form').ajaxForm({
            url: $("from").attr("action"),
            type: $("from").attr("method"),
            dataType: 'json',
            beforeSubmit: function () {},
            success: function (result) {
                /**
                 * 成功的回调函数
                 */
            },
            error:function(){
                /**
                 * 失败的回调函数
                 */
            },
            clearForm: false,//禁止清楚表单
            resetForm: false //禁止重置表单
        });
    }
</script>
</html>

注意:

这个和上面的代码几乎是一样的,区别就是上面的是 $(‘form’).ajaxSubmit,而这个是 $(‘form’).ajaxForm,且上面的input 和button的type类型都是button的,而这个的input 和button的type类型都是submit,因为$(‘form’).ajaxForm不会自动提交,所以需要我们的form表单自己来提交,所以input 和button的type类型都必须是submit,否则点击将没有任何的反应。

4.2.3  $.ajax({})方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form表单提交</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.10.0/jquery.validate.min.js"></script>
</head>
<body>
<form action="../../Controller/method" method="post">
    <input type="text" name="name" value="form表单提交"/>
    <input type="button" value="提交" onclick="submitTest()"/>
    <button type="button" onclick="submitTest()">提交</button>
</form>

</body>
<script type="text/javascript">
    function submitTest() {
        $.ajax({
            url: $("form").attr("action"),
            type: $("form").attr("method"),
            dataType: 'json',
            data: $("form").serialize(),
            success: function (result) {
                /**
                 * 执行成功时,调用的回调函数
                 * 其中返回值result的类型由上面的dataType决定,像这就是一个json类型
                 */
            },
            error:function () {
                /**
                 * 如果是异常,说明压根没有加入后台,在前台就炸了
                 * 提交异常时,执行error回调函数
                 */
            }
        });
    }
</script>
</html>

这是一个较简单的Ajax方法,我们给按钮绑定一个事件函数,在函数里编写我们的ajax代码,但是需要注意的是,我们的 <input>和<button> 的type 必须为button,否则点击一次提交,我们的form表单将提交两次,一次是form自身的submit提交,一次是我们的Ajax提交,所以type不能为submit,只能是button。

这中方法,一定要在ajax里里面的 data:项里面添加我们需要向后台传输的数据,因为这种方式并没有和我们的form表单绑定,也就是说,如果没有写data,就相当于我们没有提交任何数据到达后台。

三、JSON

1.是什么?

1.JSON指的是JavaScript 对象标记法

其实就是一种键值对的数据格式,json格式就是键值对,例如:name=value,前面是键,后面是值。

2.JSON是一种轻量级的数据交换格式

轻量级的意思是使用方面简单,没有什么复杂的其他功能,就是单单数据存储格式。

3.JSON具有自我描述性且易于理解

易于理解的意思是这种数据拿出来,我们一看就知道是什么数据,能看得懂。

4.JSON独立语言

json是数据格式,而也算是一串字符串,所以几乎所以语言都可以使用json数据。

注意:

json 的存在有两种形式。
一种是:对象的形式存在,我们叫它 json 对象。
一种是:字符串的形式存在,我们叫它 json 字符串。
一般我们要操作 json 中的数据的时候,需要 json 对象的格式。
一般我们要在客户端和服务器之间进行数据交换的时候,使用 json 字符串。
JSON.stringify() 把 json 对象转换成为 json 字符串
JSON.parse() 把 json 字符串转换成为 json 对象
 

2.JSON数据类型 

1.JSON 字符串

JSON中的字符串必须被双引号包围。

{
   "name":"彭于晏",
   "address":"四川省眉山市"
}

2.JSON 数值

JSON中的数值必须是整数或者是浮点数。

{
    "age":22
}

3.JSON 对象

JSON中可以是对象,JSON中作为值的对象必须遵守与JSON对象相同的规则。

{
    "Student":{
    "name":"胡歌",
    "age":22,
    "sex":"男",
    "id":147258369
     }
}

4.JSON 数组

JSON中的值可以是数组。

{
    "Student":["stady","cold","huya"]
}

5.JSON 布尔值

JSON中的值可以是true/false。

{
    "result":true
}

6.JSON null

JSON中的值可以是null。

{
    "username":null
}

注意:

(1)复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
(2)简单类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity,-Infinity和undefined)。
(3)字符串必须使用双引号表示,不能使用单引号。
(4)对象的键名必须放在双引号里面。
(5)数组或对象最后一个成员的后面,不能加逗号。

综合用例:

//“名称/值对”里,值可以是数组和对象,例如:
{
    "name": "Geoff Lui",
    "age": 26,
    "isChinese": true,
    "friends":["Lucy", "Lily", "Gwen"],
    "Mother": {
        "name": "Mary Lui",
        "age": 54
    }
}

3.JSON数据和Java对象的转换

1.JSON字符串转Java对象(JSON.parseObject方法)

/**
 *  JSON字符串转JSON对象
 */
public class Json1 {
    public static void main(String[] args) {
        // 定义一个JSON字符串
        String str = "{name:'孙燕姿',password:147258369,age:22,sex:'女',address:'四川省眉山市'}";
        // 将JSON字符串转换为java对象
        Demo demo = JSON.parseObject(str, Demo.class);
    System.out.println(demo.getName()+","+demo.getSex()+","+demo.getAddress()+","+demo.getPassword()+","+demo.getAge());

    }
}

结果:

2. Java对象转JSON字符串(JSON.toJSONString)

/**
 * Java对象转JSON字符串
 */
public class Json2 {
    public static void main(String[] args) {
        // 定义JAVA对象的内容
        Demo demo = new Demo("胡歌",159357147,22,"男","四川省成都市");
        // 将Java对象转化成JSON字符串
        String s = JSON.toJSONString(demo);
        System.out.println(s);

}

结果:

3.JSON字符串转JSON对象直接取出其中的值 

/**
 * JSON字符串转JSON对象并取出其中的值
 */
public class Json4 {
    public static void main(String[] args) {
        // 定义一个JSON字符串
        String str = "{name:'彭于晏',password:159369741,age:20,sex:'男',address:'四川省眉山市'}";
        JSONObject jsonObject = JSON.parseObject(str);
        System.out.println(jsonObject.getString("name") + "," + jsonObject.getInteger("password"));
    }
}

 

 4.JSON字符串转map

注意:所有情况的字符串统一使用

String str = "{name:'孙燕姿',password:147258369,age:22,sex:'女',address:'四川省眉山市'}";

4.1  第一种

        // 定义一个JSON字符串
        String str = "{name:'孙燕姿',password:147258369,age:22,sex:'女',address:'四川省眉山市'}";

        // 1.JSON字符串转换为map遍历属性键和值
        Map maps = (Map) JSON.parse(str);  // 强转为map类型
        for (Object map : maps.entrySet()) {
            System.out.println(((Map.Entry)map).getKey()+","+((Map.Entry)map).getValue());
        }

结果:

4. 2  第二种

       // 第二种
        Map mapTypes =JSON.parseObject(str);
        for(Object obj :mapTypes.keySet()){
            System.out.println("key为"+obj+"值为"+mapTypes.get(obj));
        }

 

4. 3  第三种

        // 第三种
        Map map = JSON.parseObject(str,Map.class);  // 加上Map.class 指定解析的类型
        for (Object maps : map.keySet()) {
            System.out.println("key:" + maps + "      "+"value:" + map.get(maps));
        }

结果:

4.4  第四种

        // 第四种 用JSONObject 解析成map类型
        Map jsonMap =(Map) JSONObject.parse(str);
        for (Object Jsonmaps : jsonMap.entrySet()) {
            System.out.println(((Map.Entry)Jsonmaps).getKey() + "  "+ ((Map.Entry)Jsonmaps).getValue());
        }

 

4. 5  第五种

        // 第五种 用JSONObject.parseObject
        JSONObject jsonObject = JSONObject.parseObject(str);
        for (Object map : jsonObject.entrySet()) {
            System.out.println(((Map.Entry)map).getKey() + "  "+ ((Map.Entry)map).getValue());
        }

4. 6  第六种

       // 第六种 用JSONObject.parseObject 加上Map.class 指定解析的类型
        JSONObject jsonObjectss = JSONObject.parseObject(str);
        for (Object map : jsonObjectss.entrySet()) {
            System.out.println(((Map.Entry)map).getKey() + "  "+ ((Map.Entry)map).getValue());
        }

 5.JSON字符串转JSON数组

1.JSON字符串转JSON数组

/**
 * JSON字符串(包含数组) 转 JSON数组
 */
public class Json5 {
    public static void main(String[] args) {
        String json = "{id:1,score:[{'语文':80},{'数学':100},{'英语':120}] }";
        JSONObject jsonObject = JSON.parseObject(json);
        System.out.println(jsonObject.getJSONArray("score").getJSONObject(1));

    }

结果: 

 2.JSON对象转JSON数组

        //JSON对象转JSON数组
        String jsona = "{'语文':{'周考':[78,87,80],'月考':[79,80,79]} }";
        int score =  JSON.parseObject(jsona).getJSONObject("语文").getJSONArray("月考").getIntValue(0);
        int score1 =  JSON.parseObject(jsona).getJSONObject("语文").getJSONArray("月考").getIntValue(1);
        int score2 =  JSON.parseObject(jsona).getJSONObject("语文").getJSONArray("月考").getIntValue(2);
        System.out.println(score);
        System.out.println(score1);
        System.out.println(score2);

结果:

6.JSON字符串转List

1.List集合转JSON字符串

        //对象一
        DemoModel model = new DemoModel();
        model.setId(12345678);
        model.setType("01");
        model.setZ(1111.2222);
        model.setZ1(3333.4444);
        model.setZ2(5555.6666);
        model.setZ3(7777.8888);
        //对象二
        DemoModel model1 = new DemoModel();
        model1.setId(87654321);
        model1.setType("02");
        model1.setZ(2222.1111);
        model1.setZ1(4444.3333);
        model1.setZ2(6666.5555);
        model1.setZ3(8888.7777);
        //新建List
        List list = new ArrayList();
        list.add(model);
        list.add(model1);
        //List集合转JSON字符串
        String result = toJSONString(list);
        System.out.println(result);

结果:

 2.JSON字符串转List集合

        //对象一
        DemoModel model = new DemoModel();
        model.setId(12345678);
        model.setType("01");
        model.setZ(1111.2222);
        model.setZ1(3333.4444);
        model.setZ2(5555.6666);
        model.setZ3(7777.8888);
        //对象二
        DemoModel model1 = new DemoModel();
        model1.setId(87654321);
        model1.setType("02");
        model1.setZ(2222.1111);
        model1.setZ1(4444.3333);
        model1.setZ2(6666.5555);
        model1.setZ3(8888.7777);
        //新建List
        List list = new ArrayList();
        list.add(model);
        list.add(model1);
        //List集合转JSON字符串
        String result = toJSONString(list);
        System.out.println(result);
        //JSON字符串转List集合
        List list2 = parseArray(result,DemoModel.class);
        for(int i=0;i<list2.size();i++){
            DemoModel modelTemp = (DemoModel) list2.get(i);
            System.out.println("取值 z1=" + modelTemp.getZ1());
        }
    }

结果:

 7.JSON对象(JSONObject)转list

// json数据
{
	"count": 3,
	"servers": [{
		"fault": null,
		"id": "5c1ac257-",
		"cpu_options": {
			"hw:cpu_threads": null
		}
	}]
}

// 代码

       JSONObject jsonObject = JSON.parseObject(json);
	// 获取到我们的jsonobject参数,并toJSONString
       String s = JSONArray.toJSONString(jsonObject.get("servers"));

	// 将json字符串转换为集合对象(实体类省略)
       List<AnswerCardVo> cardVos = JSONArray.parseArray(s, AnswerCardVo.class);

8.Map转JSONObject

//直接调用new方法
JSONObject jsonObject = new JSONObject(map);

4.特别情况(以上内容是接收字段与json字段一致的时候,那么不一致的时候怎么处理?)

  例:json串内容如下,要转成List

注意:可以看到,该json串中属性名是这样的OS-EXT-STS:task_state,那么我们接收的bean就无法写成这个属性名去接收,所以需要在接收Bean中使用注解@JsonProperty进行处理。

 @JsonProperty含义:@JsonProperty注解主要用于实体类的属性上,作用可以简单的理解为在反序列化的时候给属性重命名(多一个名字来识别)。

解决办法:

可以看到注解@JsonProperty中指定了要接收哪个的值,这样就可以正常转换了。

 5.JSON嵌套

1.含义:简单来说JSON 对象中可以包含另外一个 JSON 对象。

2.层层解析数据

JSON数据

{
    "error": 0,
    "status": "success",
    "results": [
        {
            "currentCity": "青岛",
            "index": [
                {
                    "title": "穿衣",
                    "zs": "较冷",
                    "tipt": "穿衣指数",
                    "des": "建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。"
                },
                {
                    "title": "紫外线强度",
                    "zs": "中等",
                    "tipt": "紫外线强度指数",
                    "des": "属中等强度紫外线辐射天气,外出时建议涂擦SPF高于15、PA+的防晒护肤品,戴帽子、太阳镜。"
                }
            ]
        }
    ]
}

解析过程:

    public static void main(String[] args) {
        String  s = "{\n" +
                "    \"error\": 0,\n" +
                "    \"status\": \"success\",\n" +
                "    \"results\": [\n" +
                "        {\n" +
                "            \"currentCity\": \"青岛\",\n" +
                "            \"index\": [\n" +
                "                {\n" +
                "                    \"title\": \"穿衣\",\n" +
                "                    \"zs\": \"较冷\",\n" +
                "                    \"tipt\": \"穿衣指数\",\n" +
                "                    \"des\": \"建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"title\": \"紫外线强度\",\n" +
                "                    \"zs\": \"中等\",\n" +
                "                    \"tipt\": \"紫外线强度指数\",\n" +
                "                    \"des\": \"属中等强度紫外线辐射天气,外出时建议涂擦SPF高于15、PA+的防晒护肤品,戴帽子、太阳镜。\"\n" +
                "                }\n" +
                "            ]\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        JSONObject jsonObject = JSONObject.parseObject(s);
        //提取出error为 0
        int error = jsonObject.getInteger("error");
        System.out.println("error:" + error);
        //提取出status为 success
        String status = jsonObject.getString("status");
        System.out.println("status:" + status);
        //注意:results中的内容带有中括号[],所以要转化为JSONArray类型的对象
        JSONArray result = jsonObject.getJSONArray("results");
        for (int i = 0; i < result.size(); i++) {
            //提取出currentCity为 青岛
            String currentCity = result.getJSONObject(i).getString("currentCity");
            System.out.println("currentCity:" + currentCity);
            //注意:index中的内容带有中括号[],所以要转化为JSONArray类型的对象
            JSONArray index = result.getJSONObject(i).getJSONArray("index");
            for (int j = 0; j < index.size(); j++) {
                String title = index.getJSONObject(j).getString("title");
                System.out.println("title:" + title);
                String zs = index.getJSONObject(j).getString("zs");
                System.out.println("zs:" + zs);
                String tipt = index.getJSONObject(j).getString("tipt");
                System.out.println("tipt:" + tipt);
                String des = index.getJSONObject(j).getString("des");
                System.out.println("des:" + des);
            }
        }

结果:

3. json解析多层嵌套并转为对应类

JSON数据

{
    "code": 1,
    "message": "查询成功",
    "data": [
        {
            "type": 1,
            "question": "地层压力与同井深的淡水静液压力之比称为地层的()。",
            "answer": "1",
            "id": 1,
            "description": "题目描述",
            "answers": [
                {
                    "isCorrect": "1",
                    "answer_name": "A的选项内容"
                },
                {
                    "isCorrect": "0",
                    "answer_name": "B的选项内容"
                },
                {
                    "isCorrect": 0,
                    "answer_name": "C的选项内容"
                },
                {
                    "isCorect": "0",
                    "answer_name": "D的选项内容"
                }
            ]
        },
        {
            "type": 1,
            "question": "起钻时,产生的抽吸压力导致井底压力()。",
            "answer": "1",
            "id": 1,
            "description": "题目描述",
            "answers": [
                {
                    "isCorrect": 1,
                    "answer_name": "A的选项内容"
                },
                {
                    "isCorrect": 0,
                    "answer_name": "B的选项内容"
                },
                {
                    "isCorrect": 0,
                    "answer_name": "C的选项内容"
                },
                {
                    "isCorrect": 0,
                    "answer_name": "D的选项内容"
                }
            ]
        }
    ]
}

实现过程:

   public static void main(String[] args) {
        String rDate = "{\n" +
                "    \"code\": 1,\n" +
                "    \"message\": \"查询成功\",\n" +
                "    \"data\": [\n" +
                "        {\n" +
                "            \"type\": 1,\n" +
                "            \"name\": \"地层压力与同井深的淡水静液压力之比称为地层的()。\",\n" +
                "            \"password\": \"1\",\n" +
                "            \"age\": 1,\n" +
                "            \"address\": \"题目描述\",\n" +
                "            \"answers\": [\n" +
                "                {\n" +
                "                    \"isCorrect\": \"1\",\n" +
                "                    \"answer_name\": \"A的选项内容\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"isCorrect\": \"0\",\n" +
                "                    \"answer_name\": \"B的选项内容\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"isCorrect\": 0,\n" +
                "                    \"answer_name\": \"C的选项内容\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"isCorect\": \"0\",\n" +
                "                    \"answer_name\": \"D的选项内容\"\n" +
                "                }\n" +
                "            ]\n" +
                "        },\n" +
                "        {\n" +
                "            \"type\": 1,\n" +
                "            \"question\": \"起钻时,产生的抽吸压力导致井底压力()。\",\n" +
                "            \"answer\": \"1\",\n" +
                "            \"id\": 1,\n" +
                "            \"description\": \"题目描述\",\n" +
                "            \"answers\": [\n" +
                "                {\n" +
                "                    \"isCorrect\": 1,\n" +
                "                    \"answer_name\": \"A的选项内容\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"isCorrect\": 0,\n" +
                "                    \"answer_name\": \"B的选项内容\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"isCorrect\": 0,\n" +
                "                    \"answer_name\": \"C的选项内容\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"isCorrect\": 0,\n" +
                "                    \"answer_name\": \"D的选项内容\"\n" +
                "                }\n" +
                "            ]\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        JSONObject rDateJSON = JSONObject.parseObject(rDate);
        //这里获取的是“data”这个JSONArray
        JSONArray data = rDateJSON.getJSONArray("data");
        // 将这个“data”数据转换到对应的类---随便找的类 有些字段没有对应上
        List<Demo> demos = JSONArray.parseArray(data.toString(), Demo.class);
        System.out.println(demos);

结果:

二、参数校验

1.概念 

在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全。
参数有两种形式:

(1)查询字符串参数(Query String Parameters参数)

一般用于GET请求,会以url string的形式进行传递。

(2)请求体参数(Request Body)

一般用于POST请求,可以使用Content-Type来指定不同参数类型。

2.使用场景

1.需要进行参数校验

(1)对外提供的开放接口. 无论是RPC,API还是HTTP接口。

(2)敏感权限入口。

(3)需要极高稳定性和可用性的方法。

(4)调用频次低的方法。

(5)销很执行开大的方法:

          参数校验的时间可以忽略不计

          如果因为参数错误会导致中间执行被退回或者错误时代价很大

 2.不需要进行参数校验

(1)可能被循环调用的方法不需要进行参数校验,但是需要在方法说明中注明外部参数的检查要求

(2)声明为private的方法,只会被本身类的代码调用:

        如果已经确定调用的方法代码传入参数已经做过检查或者肯定不会有问题,则不需要进行参数校验。

(3)底层调用频度比较高的方法。

3. 校验注解

1.校验注解

 1.@NotNull :被注解的元素必须不为null

 2.@NotBlank注解 :验证注解的元素值不为空(不为null、去除首位空格后长度为0) ,并且类型为String。   

3.@NotEmpty注解 :验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) ,并且类型为String。

4.@AssertTrue注解 :被注解的元素必须为true,并且类型为boolean。

5.@AssertFalse注解 :被注解的元素必须为false,并且类型为boolean。

6.@Min注解 :被注解的元素其值必须大于等于最小值,并且类型为int,long,float,double。

7. @Max注解:被注解的元素其值必须小于等于最小值,并且类型为int,long,float,double。

8.@DecimalMin注解 :验证注解的元素值大于等于@DecimalMin指定的value值,并且类型为BigDecimal。

9.@DecimalMax注解 :验证注解的元素值小于等于@DecimalMax指定的value值 ,并且类型为BigDecimal。

10. @Range注解 :验证注解的元素值在最小值和最大值之间,并且类型为BigDecimal,BigInteger,CharSequence,byte,short,int,long。

11.@Past注解 :被注解的元素必须为过去的一个时间,并且类型为java.util.Date。

12. @Future注解 :被注解的元素必须为未来的一个时间,并且类型为java.util.Date。

13.@Size注解 :被注解的元素的长度必须在指定范围内,并且类型为String,Array,List,Map。

14.@Length注解 :验证注解的元素值长度在min和max区间内 ,并且类型为String。

15.@Digits注解 :验证注解的元素值的整数位数和小数位数上限 ,并且类型为float,double,BigDecimal。

16.@Pattern注解 :被注解的元素必须符合指定的正则表达式,并且类型为String。

 17.@Email注解: 验证注解的元素值是Email,也可以通过regexp和flag指定自定义的email格式,类型为String。

注意:使用校验注解需要配上@Valid和@Validated

2.@Valid和@Validated

1.两者的区别

1. 分组

(1)@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。没有添加分组属性时,默认验证没有分组的验证属性。

(2)@Valid:作为标准JSR-303规范,还没有吸收分组的功能。

2. 注解地方

(1)@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上。

(2)@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上。

(3)两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。

3. 嵌套验证

(1)@Validated:用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

(2)@Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

 2.使用

1.常用参数校注解:@Null、@ NotNull、@ NotBlank、@NotEmpty。其他所有的注解,传 null 时都会被当作有效处理。

2.注解常用参数值:message(校验不通过反馈信息)。

3.用处

@Null   验证对象是否为null  
@NotNull验证对象是否不为null, 无法查检长度为0的字符串  
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.  
@NotEmpty 检查约束元素是否为NULL或者是EMPTY,用在集合类上面
 

3.具体案例

1.NotNull 

在属性上加上@NotNull 注解,message为提示信息。

 在浏览器端输入地址:http://localhost:8080/vaild1

(1)不输入参数则会报错 

 (2)只输入一个参数name或age

 (3)正确输入两个参数name和age

 其余案例基本都是这样。

 4.@Valid 嵌套校验的功能,@Validated没有

  

 在浏览器输入http://localhost:8080/user

 (1)正确的参数则嵌套成功

 (2)错误参数则提示

5.Valid注解校验不通过会抛出MethodArgumentNotValidException异常

@Valid注解的请求参数后面紧跟一个BindingResult对象,来封装校验结果

 输入错误的参数,则不会抛出异常

 6.@Validated使用场景演示

这个用法和@Valid相同,因为本来就是对@Valid注解的封装。

对于异常的抛出处理,也和@Valid一致。

7.@Validated分组校验

 @Validated分组校验,@Validated(Gropu1.class)如果指定了分组,那么只会对指定分组下的参数进行校验,别的不会管。

 1.测试Group1

 (1)group1指定分组的数据,输入错误参数,则会出现一下错误。

 (2)group1指定分组的数据输入正确,group2的参数错误,则不会进行验证。

3.总结

(1)@Valid 和 @Validated 两者都可以对数据进行校验,待校验字段上打的规则注(@NotNull, @NotEmpty等)都可以对 @Valid 和 @Validated 生效;

(2)@Valid 进行校验的时候,需要用 BindingResult 来做一个校验结果接收。当校验不通过的时候,如果手动不 return ,则并不会阻止程序的执行;

(3)@Validated 进行校验的时候,当校验不通过的时候,程序会抛出400异常,阻止方法中的代码执行,这时需要再写一个全局校验异常捕获处理类,然后返回校验提示。

(4)总体来说,@Validated 使用起来要比 @Valid 方便一些,它可以帮我们节省一定的代码,并且使得方法看上去更加的简洁。

三、全局异常处理

1.为什么要使用全局异常处理?

系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

系统的dao、service、controller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

2.全局异常处理

1.全局异常方法创建

@ControllerAdvice 即可开启全局异常处理,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用@ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。

1.1 定义基础借口类

1.2 定义枚举类

/**
 * 枚举异常类
 */
public enum ExceptionEnum implements BaseErrorInfoInterface{
    // 数据操作错误定义
    SUCCESS("2000", "成功!"),
    BODY_NOT_MATCH("4000","请求的数据格式不符!"),
    SIGNATURE_NOT_MATCH("4001","请求的数字签名不匹配!"),
    NOT_FOUND("4004", "未找到该资源!"),
    INTERNAL_SERVER_ERROR("5000", "服务器内部错误!"),
    SERVER_BUSY("5003","服务器正忙,请稍后再试!");

    /**
     * 错误码
     */
    private final String resultCode;

    /**
     * 错误描述
     */
    private final String resultMsg;

    ExceptionEnum(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }

    @Override
    public String getResultCode() {
        return resultCode;
    }

    @Override
    public String getResultMsg() {
        return resultMsg;
    }

 1.3  自定义异常类

/**
 * 自定义异常类
 */
public class BizException extends RuntimeException{
    private static final long serialVersionUID = 1L;

    /**
     * 错误码
     */
    protected String errorCode;
    /**
     * 错误信息
     */
    protected String errorMsg;

    public BizException() {
        super();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface) {
        super(errorInfoInterface.getResultCode());
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
        super(errorInfoInterface.getResultCode(), cause);
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(String errorMsg) {
        super(errorMsg);
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg) {
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg, Throwable cause) {
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }


    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }

1.4 自定义数据传输

/**
 * 自定义数据传输
 */

import com.alibaba.fastjson.JSONObject;

public class ResultResponse {
    /**
     * 响应代码
     */
    private String code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应结果
     */
    private Object result;

    public ResultResponse() {
    }

    public ResultResponse(BaseErrorInfoInterface errorInfo) {
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    /**
     * 成功
     *
     * @return
     */
    public static ResultResponse success() {
        return success(null);
    }

    /**
     * 成功
     * @param data
     * @return
     */
    public static ResultResponse success(Object data) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(ExceptionEnum.SUCCESS.getResultCode());
        rb.setMessage(ExceptionEnum.SUCCESS.getResultMsg());
        rb.setResult(data);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultResponse error(BaseErrorInfoInterface errorInfo) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultResponse error(String code, String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultResponse error( String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode("-1");
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }

1.5  自定义全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e){
        logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
        return ResultResponse.error(e.getErrorCode(),e.getErrorMsg());
    }

    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, NullPointerException e){
        logger.error("发生空指针异常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.BODY_NOT_MATCH);
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, Exception e){
        logger.error("未知异常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
    }

2.测试异常处理类 

 在浏览器上输入http://localhost:8080/add

 3.出现没有定义的异常类,如今进行处理

(1)输入错误的请求格式

 该类型为Delete,postman使用Post请求,则会报错

 

(2)处理方法

 将该异常添加到全局处理异常类

 重新尝试,即可发现成功实现捕获异常。

 自定义全局异常处理除了可以处理上述的数据格式之外,也可以处理页面的跳转,只需在新增的异常方法的返回处理上填写该跳转的路径并不使用ResponseBody 注解即可。

总结:全局异常处理器即 把错误异常统一处理的方法。Java开发过程中,不可避免的会遇到各种异常情况,如果不做处理往往会导致程序崩溃!面对这种情况,传统方式就是使用try/catch去捕获并处理异常,但是这就会导致在程序中出现大量的冗余代码,增加代码量和降低代码的可读性。我们希望的是业务层只负责业务相关操作,将异常处理重业务层抽离开来,所有的异常我们单独设立一个类去捕获和处理它,这个就是全局异常处理器,全局异常处理器将框架内所有异常进行统一管理,我们只需在可能发生异常的方法中抛出即可,降低代码冗余,提高代码可读性。

四、MyBatis

1.是什么?

MyBatis 是一款优秀的半自动的ORM持久层框架,它支持自定义 SQL、存储过程以及高级映射。

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。 

MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1. 什么是ORM

OBject Relation Mapping 对象关系映射

对象指的是面向面向对象,关系指的是数据库中的表,例如Java语言中的POJO类与数据库模型之间的对应关系。

2.MyBaits工作原理

1.JDBC核心对象

  1. DriverManager,数据库驱动管理对象。
  2. Connection,数据库连接对象。
  3. Statement | PrepareStatement ,操作数据库SQL语句对象。
  4. ResultSet,结果集对象。

2.MyBaits核心对象


(1)SqlSession对象,该对象包含了执行SQL语句的所有方法,例如JDBC里面Connection

对象                                              说明
Executor接口    执行器.统一调度其他三个对象执行对应的SQL
StatementHandler    使用的数据库中的Statement执行操作 相当于字符串拼接
PrepareStatement    使用SQL传参的方式处理
ResultHandler    对最后的结果进行封装


(2)Executor接口,将传递过来的参数动态生成SQL语句,负责查询缓存。

(3)MappedStatement对象,该对象负责对SQL封装,用于存储需要映射的SQL语句及参数等信息

(4)ResultHandler对象,用户返回结果集合,封装成最红想要的数据类型,可以自定义返回类型

3.无索引批量插入数据

1.使用MyBatis.xml中的foreach循环

1.多条数据批量插入的写法有所不同,以集合的形式插入,需要借助<foreach></foreach>,代码实例如下所示:
注意<foreach></foreach>键值对中各个参数的写法:
    (1)collection:为必填值,值为要迭代循环的集合类型,情况有多种:
    入参是List类型的时候,collection属性值为list。
    入参是Map类型的时候,collection 属性值为map的key值。
    (2)item:每一个元素进行迭代时的别名,可自行定义,省事就直接用“item”即可。
    (3)index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是map时,这个值是map的key。
    (4)separator: 每次循环的分隔符。

2.Mapper接口代码如下

3.Mapper.xml代码如下

 4.用test测试

5.结果如下

2.使用普通循环的方式批量插入数据

这个是使用for循环,循环单条插入数据库,每一次循环伴随SqlSession的打开和关闭都是一个单独的事务提交,性能最差。

1.Mapper接口代码如下

2. Mapper.xml代码如下

3.test测试

 4.结果如下

3.ExecutorType.BATCH批量插入

 1.Mybatis内置的ExecutorType有3种,默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句。

2.test测试

 4.批量更新数据

1.使用foreach更新数据

1.Mapper接口

2. Mapper.xml代码如下

 3.test测试

4.结果如下

2.使用case when 实现批量更新 

1.参数含义

(1)prefix:在trim标签内sql语句加上前缀。

(2)suffix:在trim标签内sql语句加上后缀。

(3)prefixOverrides:指定去除多余的前缀内容

(4)suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=”,”,去除trim标签内sql语句多余的后缀”,”。

2.Mapper代码

 3.Mapper.xml 代码

4.test测试

5.结果

 3.有索引批量插入数据,主键冲突则更新数据

使用: ON DUPLICATE KEY UPDATE

1.含义

ON DUPLICATE key update是根据索引字段是否重复来判断是否执行,如果重复则执行update,否则则执行insert。

优先级主键>唯一索引

(1)当主键重复时则执行update
(2)当主键不重复,唯一索引重复时也执行update
(3)当主键和唯一索引值都不重复才执行insert

2.Mapper代码

3.Mapper.xml代码

 第一部分是正常的批量插入语句。

第二部分是 ON DUPLICATE KEY UPDATE 会进行判断,冲突则执行后面的更新语句,不冲突则正常执行insert语句。

第三部分是冲突后执行的更新语句,age是主键,age= values(age)  意思是 当age重复是,修改其剩余的内容,age不变。values(name) 是将值修改为新增的值。

4.常见的查询操作

1.传递单个参数时

1.Mapper接口

 2.Mapper.xml

3. test测试

4.结果

2.传递多个参数 

1.通过map集合

(1)Mapper接口

(2)Mapper.xml

(3)test测试

(4)结果

2.使用@Param()参数指定参数的名称 

(1)Mapper接口

(2)Mapper.xml

(3)test测试

 (4)结果

3.使用对象接受 

(1)Mapper接口

(2)Mapper.xml

(3)test测试

 (4)结果

4.List集合

(1)Mapper接口

 (2)Mapper.xml

(3)test测试

(4)结果

 注意:

若sql语句查询的结果为多条时,一定不能以实体类类型作为方法的返回值;否则会抛出TooManyResultsExecption

若sql语句查询的结果为1条时,此时可以使用实体类类型或list集合类型作为方法的返回值

 5. Map集合

(1)Mapper接口

(2)Mapper.xml

(3)test测试

 (4)结果

6.List<Map>

将每一条数据查询为一个map集合中,将map集合放入List集合中

在接口文件中添加相应的查询所有的信息为一个map集合

 (1)Mapper接口

(2)Mapper.xml

   

(3)test测试

  

(4)结果

五、Mybatis-plus

1.是什么

MyBatis-Plus(简称 MP)是一个 Mybatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

(1)无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
(2)损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作,BaseMapper。
(3)强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,简单的CRUD操作不用自己编写。
(4)支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错。
(5)支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 – Sequence),可自由配置,完美解决主键问题。
(6)支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作。
(7)支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )。
(8)内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用(自动生成代码)。
(9)内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询。
(10)分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库。
(11)内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询。
(12)内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作。

二、BaseMapper CRUD 接口


说明:

1.通用 CRUD 封装BaseMapper接口,为Mybatis−Plus启动时自动解析实体表关系映射转换Mybatis内部对象注入容器。
2.泛型 T 为任意实体对象。
3.参数Serializable 为任意类型主键 Mybatis−Plus不推荐使用复合主键约定每一张表都有自己的唯一 id 主键。
4.对象Wrapper为 条件构造器。

1.前提

1.entity 

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("emp")
@ApiModel(value="Emp对象", description="")
public class Emp implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "id")
    private Integer id;

    @ApiModelProperty(value = "姓名")
    @TableField("name")
    private String name;

    @ApiModelProperty(value = "性别")
    @TableField("sex")
    private String sex;

    @ApiModelProperty(value = "年龄")
    @TableField("age")
    private Integer age;

    @ApiModelProperty(value = "地址")
    @TableField("address")
    private String address;

 2.Mapper接口需要继承BaseMapper

 2.实现CRUD

1.新增

(1)测试 

 (2)结果

 

2.删除

2.1 根据id删除

(1)测试

 

 (2)结果

成功删除

 

2.2 批量删除

(1)测试

(2)结果 

 

测试前 

 测试后

2.3 map 条件删除

(1)测试

 

 (2)结果

 测试前

测试后

 

2.4  wrapper 条件删除 

(1)测试

 (2)结果

测试前

测试后

 

3.修改

3.1 根据id 进行修改

(1)测试

 

 (2)结果

 测试前

测试后

 

3.2 使用updateWrapper 条件修改

(1)测试

 

 (2)结果

测试前

 

 测试后

 4.查询

4.1 id查询

(1)测试

(2)结果

 

4.2 ids批量查询

(1)测试

(2)结果

 

4.3 查询全部

(1)测试

(2)结果

 

4.4 map 查询

(1)测试

 

 (2)结果

 

4.5 条件构造器查询

(1)测试

 

(2)结果

 

三、IBaseService CRUD 接口 

说明:

(1)通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get查询单行、remove删除、list查询集合、page分页 ,前缀命名方式区分 Mapper 层避免混淆。
(2)泛型 T 为任意实体对象。
(3)建议如果存在自定义通用 Service 方法的可能,请创建自己的IBaseService继承 Mybatis-Plus 提供的基类。
(4)对象Wrapper 为 条件构造器
注意:BaseMapper不支持批量操作,IBaseService支持批量操作。

2.实现CRUD

1.查询

1.1  根据id查询

(1)测试

(2)结果

 

1.2  根据ids 批量查询

(1)测试

(2)结果

 

1.3  根据map查询

(1)测试

 

(2)结果

 

1.4 查询全部

(1)测试

 

(2)结果

 

1.5  根据条件构造器查询

(1)测试

(2)结果

2.insert

2.1 按实体类新增

(1)测试

 

(2)结果

 

数据库:

2.2 批量新增

(1)测试

 

(2)结果

 

3.修改

3.1  根据id修改

(1)测试

 

(2)结果

 

 

3.2  批量修改

(1)测试

 

(2)结果

 

实现前

 

实现后

 

3.3 根据条件构造器修改

(1)测试

 

(2)结果

 

数据库

4. 删除

4.1 根据id删除

(1)测试

 

 (2)结果

成功删除

 

4.2 批量删除

(1)测试

 

(2)结果

成功删除

4.3 根据map删除

(1)测试

 

(2) 结果

成功删除

 

4.4 根据条件构造器删除

(1)测试

(2)结果

 

成功删除

 

 

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年12月22日
下一篇 2023年12月22日

相关推荐