【SpringMVC从入门到实战教程】第五章 SpringMVC JSON数据交互

五、SpringMVC JSON数据交互

5.1 同步和异步回顾

在这里插入图片描述

5.1.1 同步请求

  • 当浏览器向服务器发送同步请求时,服务处理同步请求的过程中,浏览器会处于等待的状态,只有接收到服务器的响应之后才能进行后续操作。
  • 服务器处理完请求把数据响应给浏览器并覆盖浏览器内存中原有的数据,浏览器——重新加载页面(执行重定向或请求转发)并展示服务器响应的数据
//1、客户端浏览器发送用户的登录请求
登录表单 -> 点击submit按钮

//2、需要等待响应,才能执行后续操作
//...

5.1.2 异步请求

  • 当浏览器向服务器发送异步请求时,服务处理异步请求的过程中,浏览器无需等待服务器的响应,即可进行后续操作。
  • 服务器处理完请求响应字符串数据给浏览器,浏览器——无需加载页面(不再执行重定向或请求转发),可实现页面的局部变化
//1、注册表单的用户名的校验,用户填写完用户名就发送异步请求
$.ajax({
    url:"userNameUnique.do",
    data:{
        userName: $("#userName").val()
    },
    success:function(){
        //请求成功的回调函数
    }
})

//2、ajax方法执行之后,无需等待回调执行,可以继续执行后续js代码

异步请求的原理:

	浏览器把请求交给代理对象—XMLHttpRequest(绝大多数浏览器都内置了这个对象),由代理对象向服务器发起请求,接收、解析服务器响应的数据,并把数据更新到浏览器指定的控件上。从而实现了页面数据的局部刷新。

在这里插入图片描述

5.2 Ajax和JSON回顾

5.2.1 Ajax

	Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
	
	通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

jQuery.ajax(url,[settings]):

	通过 HTTP 请求加载远程数据。

	jQuery 底层 AJAX 实现。简单易用的高层实现见 `$.get`, `$.post` 等。`$.ajax()` 返回其创建的 XMLHttpRequest 对象。大多数情况下你无需直接操作该函数,除非你需要操作不常用的选项,以获得更多的灵活性。

参数:

    url: 一个用来包含发送请求的URL字符串。

    settings: AJAX 请求设置。所有选项都是可选的。

settings常用选项:

参数名参数类型描述
asyncBoolean(默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
contentTypeString(默认: “application/x-www-form-urlencoded”) 发送信息至服务器时内容编码类型。默认值适合大多数情况。如果你明确地传递了一个content-type给 $.ajax() 那么他必定会发送给服务器(即使没有数据要发送)
dataObject,String发送到服务器的数据。将自动转换为请求字符串格式。GET 请求中将附加在 URL 后。查看 processData 选项说明以禁止此自动转换。必须为 Key/Value 格式。如果为数组,jQuery 将自动为不同值对应同一个名称。如 {foo:[“bar1”, “bar2”]} 转换为 “&foo=bar1&foo=bar2”。
dataTypeString预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如XML MIME类型就被识别为XML。在1.4中,JSON就会生成一个JavaScript对象,而script则会执行这个脚本。随后服务器端返回的数据会根据这个值解析后,传递给回调函数
errorFunction(默认: 自动判断 (xml 或 html)) 请求失败时调用此函数。有以下三个参数:XMLHttpRequest 对象、错误信息、(可选)捕获的异常对象。如果发生了错误,错误信息(第二个参数)除了得到null之外,还可能是"timeout", “error”, “notmodified” 和 “parsererror”。
headersmapDefault: {},一个额外的"{键:值}"对映射到请求一起发送。此设置被设置之前beforeSend函数被调用;因此,消息头中的值设置可以在覆盖beforeSend函数范围内的任何设置。
timeoutNumber设置请求超时时间(毫秒)。此设置将覆盖全局设置。
typeString(默认: “GET”) 请求方式 (“POST” 或 “GET”), 默认为 “GET”。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
urlString(默认: 当前页地址) 发送请求的地址。

5.2.2 JSON

  • JSON(JavaScript Object Notation,JS 对象简谱) 是一种轻量级的数据交换格式;
  • 基于ECMAScript的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据;
  • 简洁和清晰的层次结构使得JSON成为理想的数据交换语言;
  • 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率;

index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <h1>首页</h1>
        <a href="views/json.jsp">JSON</a><br>
        <a href="views/request.jsp">请求</a><br>
        <a href="views/response.jsp">响应</a><br>
    </div>
</body>
</html>

json.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
    <script type="text/javascript">
        //JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
        //这是一个对象,注意键名也是可以使用引号包裹的
        var obj = {
            name: 'tom',
            age: 20
        };
        
        //这是一个 JSON 字符串,本质是一个字符串
        var json = '{"name": "jerry", "age": 19}';

        //JSON字符串转换为JS对象,使用JSON.parse()方法:
        var obj2 = JSON.parse(json);

        //JS对象转换为JSON字符串,使用JSON.stringify()方法:
        var json2 = JSON.stringify(obj);
    </script>
</head>
<body>
</body>
</html>

5.3 SpringMVC处理异步请求

	为实现浏览器与控制器类之间的 JSON 数据交互,Spring MVC 提供了 MappingJackson2HttpMessageConverter 实现类默认处理 JSON 格式请求响应。该实现类利用 Jackson 开源包读写 JSON 数据,将 Java 对象转换为 JSON 对象和 XML 文档,同时也可以将 JSON 对象和 XML 文档转换为 Java 对象。

5.3.1 请求

  • 客户端请求的是key/value值,contentType为 application/x-www-form-urlencoded 默认值,服务器端不需要处理,即可获取数据。
  • 客户端请求的是json字符串,需要指定contentType为 application/json,并且在服务器端需要使用@RequestBody注解将json串转成java对象

5.3.2 响应

  • 需要使用@ResponseBody注解将java对象转成json串输出

5.4 实现过程

5.4.1 导入jackson包

	Jackson 是最流行的 json 解析器之一。Spring MVC 的默认 json 解析器便是 Jackson。
	
	Jackson 优点很多。Jackson 所依赖的 jar 包较少,简单易用。与其他 Java 的 json 的框架 Gson 等相比,Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
	
	Jackson 的 1.x 版本的包名是 org.codehaus.jackson ,当升级到 2.x 版本时,包名变为 com.fasterxml.jackson。
	
	三个核心模块:
		jackson-core: 核心包。定义了低级的流式API,包括了JSON处理细节。
        jackson-annotations: 注解包。包含了Jackson的注解。
        jackson-databind: 数据绑定包。实现了对象和JSON之间的转换,这个包依赖上面两个包。

	Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。
        
	其他优秀的json解析工具:Google的Gson、阿里巴巴的FastJson等。

方式一:引入jar包

在这里插入图片描述

方式二:maven依赖配置

<dependencies>
    <!-- spring核心包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springbean包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springcontext包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- spring表达式包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springAOP包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springAspects包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- spring对web的支持 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springwebMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>

    <!-- 配置javaweb环境 -->
    <!-- servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <!-- jsp-api -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.1</version>
        <scope>provided</scope>
    </dependency>
    <!-- jstl -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.5</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.5</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.5</version>
    </dependency>
</dependencies>

注意:spring4.x须使用jackson2.x版本,而spring3.x版本使用jackson1.x版本。

5.4.2 配置

在处理器适配器中配置json转换器:

<!--在处理器适配器中配置json转换器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                        <value>text/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </list>
    </property>
</bean>

注意:如果使用<mvc:annotation-driven/>则不用定义上边的内容。

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        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/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- springmvc的注解式开发 -->
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.newcapec.controller"/>

    <!-- MVC注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 配置视图地址的前缀和后缀:简化视图地址 -->
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

5.4.3 POJO

Dept.java:

public class Dept {
    
    private Integer deptno;
    private String dname;

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                '}';
    }
}

Emp.java:

public class Emp {

    private Integer empno;
    private String ename;
    private String job;
    private Double sal;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date hiredate;
    private Dept dept;

    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", sal=" + sal +
                ", hiredate=" + hiredate +
                ", dept=" + dept +
                '}';
    }
}

5.4.4 请求key/value

request.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        //key-value值
        function sendKeyValue() {
            //js的字面量对象
            var emp = {
                empno: 1001,
                ename: 'tom',
                job: 'staff',
                sal: 4500,
                hiredate: '2022-01-09',
                'dept.deptno': 10,
                'dept.dname': 'HR'
            };
            
            //发送异步请求
            $.ajax('sendKeyValue.do', {
                type: 'post',
                data: emp,
                //内容类型:将数据转换为keyValue向服务器提交
                contentType: 'application/x-www-form-urlencoded',
                success: function (resp) {
                    alert(resp);
                }
            });
        }
    </script>
</head>
<body>
<div style="text-align: center">
    <p><a href="javascript:sendKeyValue()">向服务器端发送key/value值</a></p>
    <p><a href="javascript:sendJson()">向服务器端发送json值</a></p>
</div>
</body>
</html>

Controller:

@Controller
public class JsonController {

    @RequestMapping("sendKeyValue.do")
    public void sendKeyValue(Emp emp, HttpServletResponse response) throws IOException {
        System.out.println("请求数据:" + emp);
        response.getWriter().write("success");
    }
}

请求内容类型:

在这里插入图片描述

请求数据:

在这里插入图片描述

请求数据源:

在这里插入图片描述

5.4.5 请求json字符串

request.jsp页面js:

//json字符串格式
function sendJson() {
    //js的字面量对象
    var emp = {
        empno: 1002,
        ename: 'jerry',
        job: 'manager',
        sal: 6800,
        hiredate: '2022-01-09',
        //区别于key/value的写法
        dept: {
            deptno: 20,
            dname: 'SALE'
        }
    };
    
    //发送异步请求
    $.ajax('sendJson.do', {
        type: 'post',
        data: JSON.stringify(emp),
        //内容类型:告知服务器提交数据为json字符串
        contentType: 'application/json',
        success: function (resp) {
            alert(resp);
        }
    });
}

Controller:

@Controller
public class JsonController {

    /**
     * @RequestBody
     * 位置:形参
     * 作用:将前端提交的json字符串,转换为Java对象
     */
    @RequestMapping("/sendJson.do")
    public void sendJson(@RequestBody Emp emp, HttpServletResponse response) throws IOException {
        System.out.println("请求数据:" + emp);
        response.getWriter().write("success");
    }
}

请求内容类型:

在这里插入图片描述

请求数据:

在这里插入图片描述

请求数据源:

在这里插入图片描述

5.4.6 响应单数据字符串

response.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        function responseString() {
            $.ajax('responseString.do', {
                type: 'get',
                success: function (resp) {
                    alert(resp);
                }
            });
        }
    </script>
</head>
<body>
<div style="text-align: center">
    <p><a href="javascript:responseString()">获取普通字符串数据</a></p>
    <p><a href="javascript:responseObject()">获取对象数据</a></p>
    <p><a href="javascript:responseList()">获取批量数据</a></p>
    <div id="data">
    </div>
    <table border="1" width="500" align="center">
        <thead>
        <tr>
            <th>员工编号</th>
            <th>员工姓名</th>
            <th>员工岗位</th>
            <th>员工薪资</th>
            <th>入职日期</th>
        </tr>
        </thead>
        <tbody id="tab"></tbody>
    </table>
</div>
</body>
</html>

Controller:

@Controller
public class JsonController {

    /*
     * @ResponseBody
     * 位置:方法和类
     * 作用:将当前方法的返回值以json字符串的形式响应到前端
     *      即使返回值为String类型,也不再进行页面跳转(返回值不再是视图名),就是需要响应的数据
     */
    @ResponseBody
    @RequestMapping("responseString.do")
    public String responseString(){
        return "success";
    }
}

5.4.7 响应json对象字符串

response.jsp页面js:

function responseObject() {
    $.ajax('responseObject.do', {
        type: 'get',
        success: function(resp) {
            //在回调函数的参数中直接获取是js的字面对象
            // alert(resp);
            //jquery中的ajax方法,在接收到后台响应的json字符串时,会自动进行json->object的转换
            var str = '<p>员工编号:' + resp.empno + '</p>';
            str += '<p>员工姓名:' + resp.ename + '</p>';
            str += '<p>员工岗位:' + resp.job + '</p>';
            str += '<p>员工薪资:' + resp.sal + '</p>';
            str += '<p>入职日期:' + resp.hiredate + '</p>';
            $('#data').html(str);
        }
    });
}

Controller:

@Controller
public class JsonController {

    /**
     * 响应json数据
     * 响应单个数据(一个实体对象)
     *
     * @ResponseBody
     * 位置:方法,返回值
     * 作用:将该方法的返回值转换为json字符串向客户端响应
     */
    @ResponseBody
    @RequestMapping("/responseObject.do")
    public Emp responseObject(){
        //模拟数据库中的查询
        Emp emp = new Emp();
        emp.setEmpno(201);
        emp.setEname("chris");
        emp.setJob("manager");
        emp.setHiredate(new Date());
        emp.setSal(6300.0);
        //在同步请求中,将数据存放在域对象中...
        //异步请求:直接返回对象
        return emp;
    }
}

测试结果:

在这里插入图片描述

5.4.8 响应json数组字符串

response.jsp页面js:

function responseList() {
    $.ajax('responseList.do', {
        type: 'get',
        success: function(resp) {
            //在回调函数的参数中直接获取是js的字面对象数组
            var str = '';
            for(var i in resp) {
                var emp = resp[i];
                str += '<tr>';
                str += '<td>' + emp.empno + '</td>';
                str += '<td>' + emp.ename + '</td>';
                str += '<td>' + emp.job + '</td>';
                str += '<td>' + emp.sal + '</td>';
                str += '<td>' + emp.hiredate + '</td>';
                str += '</tr>';
            }
            $('#tab').html(str);
        }
    });
}

Controller方法:

@Controller
public class JsonController {

    /**
     * 响应json数据
     * 响应批量数据(一个集合,集合中存放的是多个实体对象)
     *
     * @ResponseBody
     * 位置:方法,返回值
     * 作用:将该方法的返回值转换为json字符串向客户端响应
     */
    @ResponseBody
    @RequestMapping("/responseList.do")
    public List<Emp> responseList(){
        //模拟数据库中的查询
        Emp emp1 = new Emp();
        emp1.setEmpno(201);
        emp1.setEname("chris");
        emp1.setJob("manager");
        emp1.setHiredate(new Date());
        emp1.setSal(6300.0);
        
        Emp emp2 = new Emp();
        emp2.setEmpno(202);
        emp2.setEname("tom");
        emp2.setJob("manager");
        emp2.setHiredate(new Date());
        emp2.setSal(6300.0);
        
        Emp emp3 = new Emp();
        emp3.setEmpno(203);
        emp3.setEname("cherry");
        emp3.setJob("manager");
        emp3.setHiredate(new Date());
        emp3.setSal(6300.0);
        
        List<Emp> list = new ArrayList<>();
        list.add(emp1);
        list.add(emp2);
        list.add(emp3);
        //在同步请求中,将数据存放在域对象中...
        //异步请求:直接返回对象
        return list;
    }
}

测试结果:

在这里插入图片描述

5.4.9 日期类型处理

POJO类中有日期类型的属性,只需在属性上加上@JsonFormat注解即可:

public class Emp {

    private Integer empno;
    private String ename;
    private String job;
    private Double sal;
    /**
     * @DateTimeFormat 将客户端提交的字符串转换为Date类型
     * @JsonFormat 将日期类型转换为指定格式字符串
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date hiredate;
    private Dept dept;

    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
            "empno=" + empno +
            ", ename='" + ename + '\'' +
            ", job='" + job + '\'' +
            ", sal=" + sal +
            ", hiredate=" + hiredate +
            ", dept=" + dept +
            '}';
    }
}
public String getJob() {
    return job;
}

public void setJob(String job) {
    this.job = job;
}

public Double getSal() {
    return sal;
}

public void setSal(Double sal) {
    this.sal = sal;
}

public Date getHiredate() {
    return hiredate;
}

public void setHiredate(Date hiredate) {
    this.hiredate = hiredate;
}

public Dept getDept() {
    return dept;
}

public void setDept(Dept dept) {
    this.dept = dept;
}

@Override
public String toString() {
    return "Emp{" +
        "empno=" + empno +
        ", ename='" + ename + '\'' +
        ", job='" + job + '\'' +
        ", sal=" + sal +
        ", hiredate=" + hiredate +
        ", dept=" + dept +
        '}';
}

}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是波哩个波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值