SpringMVC的视图
一、SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户
二、SpringMVC视图的种类很多,默认有转发视图和重定向视图
三、当工程引入jstl的依赖,转发视图会自动转换为JstlView
四、若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView
ThymeleafView
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转
@RequestMapping("/testThymeleafView")
public String testThymeleafView(){
return "success";
}
转发视图
一、当前我们访问的很多页面是不满足Thymeleaf视图解析器的,比如在实现转发时,我们要访问的页面或者我们要转发的资源就不符合Thymeleaf视图解析器的规则。
二、SpringMVC中默认的转发视图是InternalResourceView
三、SpringMVC中创建转发视图的情况:当控制器方法中所设置的视图名称以forward:
为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀forward:
去掉,剩余部分作为最终路径通过转发的方式实现跳转,例如forward:/
、forward:/employee
@RequestMapping("/testForward")
public String testForward(){
return "forward:/testThymeleafView";// 转发到上面那个请求:forward:要转发到的资源的路径
}
四、解析return "forward:/testThymeleafView";
会创建两次视图,首先将前缀forward:
去掉,剩余的部分/testThymeleafView
通过转发访问,这个过程会创建转发视图InternalResourceView,但是因为/testThymeleafView
也是一个请求,所以当找到/testThymeleafView
的请求映射testThymeleafView
方法时,还会再创建一个ThymeleafView
重定向视图
一、SpringMVC中默认的重定向视图是RedirectView
二、当控制器方法中所设置的视图名称以redirect:
为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀redirect:
去掉,剩余部分作为最终路径通过重定向的方式实现跳转,例如redirect:/
、redirect:/employee
@RequestMapping("/testRedirect")
public String testRedirect(){
return "redirect:/testThymeleafView";// 重定向到上面那个请求:redirect:要重定向到的资源的路径
}
三、重定向视图在解析时,会先将redirect:
前缀去掉,然后会判断剩余部分是否以/开头,若是则会自动拼接上下文路径
四、重定向可以改变地址栏中的地址,相当于浏览器再次发送请求去访问,像我们某个操作成功后,如操作成功、删除成功之后和原来的请求就没有关系了,这就需要重定向跳转,如果用转发的话会保留上一次请求路径
五、转发与重定向的区别:
- 转发是一次请求(这个一次请求指的是浏览器发送了一次请求),第一次时浏览器发送请求,第二次请求发生在服务器内部,所以地址栏还是浏览器发送请求的那个地址,地址栏中的地址不变
- 重定向是两次请求,第一次访问servlet,第二次访问重定向的地址,地址栏中的地址会变为重定向的地址
- 转发可以获取请求域中的数据,重定向不可以,因为重定向是两次请求,两次请求对应两个request对象,而转发是一次请求,用到的request对象是同一个。(注意:能否获取域对象中的数据,主要看你使用的对象是不是同一个)
- 转发可以访问WEB-INF中的资源,重定向不可以,因为WEB-INF中的资源具有安全性、隐藏性,只能通过服务器内部来访问,不能通过浏览器来访问
- 转发不能跨域,重定向可以,因为转发是发生在服务器内部的,只能访问服务器内部资源,重定向是浏览器发送了两次请求,通过浏览器可以访问任何资源,比如从我们的项目中重定向到百度,
视图控制器view-controller
一、视图控制器view-controller是springMVC配置文件的一个标签,用于实现请求地址与视图之间的映射关系,之前我们写了一个请求映射:
@RequestMapping("/testThymeleafView")
public String testThymeleafView(){
return "success";
}
当我们访问路径为/testThymeleafView时,可以通过视图名称success,通过视图解析器解析来跳转到相对应的页面,这种请求映射我们会写很多,比如我们在实现添加功能时,添加成功后跳转到添加页面,这时是不需要有任何其他请求的处理,我们只需要写一个请求映射,对应一个请求路径,在他对应的控制器方法中返回视图名称即可,像这种控制器方法中不需要处理其他请求的过程时,我们可以使用view-controller标签来处理请求映射的关系,也就是说,当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示,在springMVC.xml
文件中配置:
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:view-controller path="/test_view" view-name="test_view"></mvc:view-controller>
<mvc:view-controller path="/test_rest" view-name="test_rest"></mvc:view-controller>
其中,path
指定请求路径,view-name
指定视图名称
二、当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:<mvc:annotation-driven />
InternalResourceViewResolver
在springMVC.xml中配置:
<context:component-scan base-package="com.atguigu.mvc.controller"></context:component-scan>
<!-- 配置视图解析器 在JSP中,不涉及任何前缀他也是转发的效果,InternalResourceViewResolver是springMVC中默认的转发视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/templates/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
/bean>
index.jsp中代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--上面这一行是jsp指令,用来设置当前页面的信息,比如上面这行代码的意思是:
内容类型是以文本形式存在的html页面,使用UTF-8编码,JSP支持语言:Java
JSP是可以直接访问的,项目一启动,默认访问index.jsp--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<%--${pageContext.request.contextPath}动态获取上下文对象--%>
<a href="${pageContext.request.contextPath}/success">success.jsp</a>
</body>
</html>
JspController.java中代码:
@Controller
public class JspController {
@RequestMapping("/success")
public String success(){
return "success";
}
}
RESTful
一、RESTful是一种软件架构的风格/格式,不以?传参,将所有的参数以/拼接到请求路径中
二、REST:Representational State Transfer,表现层(前端的视图页面到后端的控制层)资源状态转移。
- 把项目部署到服务器上之后,档期那工程中的内容在服务器上都叫资源。资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。
- 资源的状态是资源的表现形式,也就是资源的表述,比如html页面、音频、类等。资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。
- 状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述,就是浏览器向服务器发送请求(请求某个资源),服务器响应这一过程。通过转移和操作资源的表述,来间接实现操作资源的目的。
三、RESTful的实现
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE用来删除资源。
REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。
RESTful模拟操作用户资源
使用RESTFul模拟用户资源的增删改查
请求路径 | 请求方法 | 操作 |
---|---|---|
/user | GET | 查询所有用户信息 |
/user/1 | GET | 根据用户id查询用户信息 |
/user | POST | 添加用户信息 |
/user/1 | DELETE | 删除用户信息 |
/user | PUT | 修改用户信息 |
get和post请求
@Controller
public class UserController {
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String getAllUser(){
System.out.println("查询所有用户信息");
return "success";
}
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public String getUserById(){
System.out.println("根据id查询用户信息");
return "success";
}
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String insertUser(String username, String password){
System.out.println("添加用户信息:"+username+","+password);
return "success";
}
}
前端代码:
<body>
<a th:href="@{/user}">查询所有用户信息</a><br>
<a th:href="@{/user/1}">根据id查询用户信息</a><br>
<form th:action="@{/user}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="添加"><br>
</form>
HiddenHttpMethodFilter
一、由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?SpringMVC提供了HiddenHttpMethodFilter帮助我们将POST请求转换为DELETE或PUT请求
二、HiddenHttpMethodFilter处理put和delete请求的条件:
- 当前请求的请求方式必须为post
- 当前请求必须传输请求参数_method
满足以上条件,HiddenHttpMethodFilter过滤器就会将当前请求的请求方式转换为请求参数_method的值,因此请求参数_method的值才是最终的请求方式
<!--1. 当前请求的请求方式必须为post-->
<form th:action="@{/user}" method="post">
<!--1. 当前请求必须传输请求参数_method,_method的值才是最终的请求方式-->
<input type="hidden" name="_method" value="PUT">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="修改"><br>
</form>
三、在web.xml
中注册HiddenHttpMethodFilter:
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filterclass>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
四、映射方法:
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public String updateUser(String username, String password){
System.out.println("修改用户信息:"+username+","+password);
return "success";
}
五、目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter。在web.xml
中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter,因为在CharacterEncodingFilter中通过request.setCharacterEncoding(encoding)
方法设置字符集的request.setCharacterEncoding(encoding)
方法要求前面不能有任何获取请求参数的操作,而HiddenHttpMethodFilter恰恰有一个获取请求方式的操作:String paramValue = request.getParameter(this.methodParam);
,他获取了参数_method
,所以如果先注册HiddenHttpMethodFilter,再注册CharacterEncodingFilter,CharacterEncodingFilter会失效
RESTful案例
一、新建项目springMVC-rest
,如前述搭建环境
二、搭建实体类src/main/java/com/atguigu/rest/bean
:
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getLastName() {return lastName;}
public void setLastName(String lastName) {this.lastName = lastName;}
public String getEmail() {return email;}
public void setEmail(String email) {this.email = email;}
public Integer getGender() {return gender;}
public void setGender(Integer gender) {this.gender = gender;}
public Employee(Integer id, String lastName, String email, Integer gender) {
super();
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
}
public Employee() {}
}
三、准备dao模拟数据
@Repository
public class EmployeeDao {
// 本例中我们没有service,需要从controller直接访问DAO,所以再DAO中要创建一个employees对象
private static Map<Integer, Employee> employees = null;
static{
employees = new HashMap<Integer, Employee>();
employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
}
private static Integer initId = 1006;
public void save(Employee employee){
if(employee.getId() == null){
employee.setId(initId++);
}
employees.put(employee.getId(), employee);
}
public Collection<Employee> getAll(){return employees.values();}
public Employee get(Integer id){return employees.get(id);}
public void delete(Integer id){employees.remove(id);}
}
具体功能
功能 | URL地址 | 请求方式 |
---|---|---|
访问首页 | / | GET |
查询全部数据 | /employee | GET |
删除 | /employee/2 | DELETE |
跳转到添加数据页面 | /toAdd | GET |
执行保存 | /employee | POST |
跳转到更新数据页面 | /employee/2 | GET |
执行更新 | /employee | PUT |
访问首页
一、在springMVC.xml
配置视图控制器:
<!--配置视图控制器-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<!--开启mvc注解驱动-->
<mvc:annotation-driven />
二、创建页面:
<body>
<h1>首页</h1>
<a th:href="@{/employee}">访问员工信息</a>
</body>
三、配置tomcat
查询所有员工数据
一、控制器方法
@RequestMapping(value = "/employee", method = RequestMethod.GET)
public String getEmployeeList(Model model){
Collection<Employee> employeeList = employeeDao.getAll();
model.addAttribute("employeeList", employeeList);
return "employee_list";
}
二、创建employee_list.html
,页面代码如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Employee Info</title>
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
</head>
<body>
<table border="1" cellpadding="0" cellspacing="0" style="text-align:
center;" id="dataTable">
<tr>
<th colspan="5">Employee Info</th>
</tr>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>options(<a th:href="@{/toAdd}">add</a>)</th>
</tr>
<tr th:each="employee : ${employeeList}">
<td th:text="${employee.id}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td th:text="${employee.gender}"></td>
<td>
<a class="deleteA" @click="deleteEmployee"
th:href="@{'/employee/'+${employee.id}}">delete</a>
<a th:href="@{'/employee/'+${employee.id}}">update</a>
</td>
</tr>
</table>
</body>
</html>
删除
一、创建处理delete请求方式的表单
<!-- 作用:通过超链接控制表单的提交,将post请求转换为delete请求 -->
<form id="delete_form" method="post">
<!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 -->
<input type="hidden" name="_method" value="delete"/>
</form>
二、删除超链接绑定点击事件
- 引入vue.js:
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
- 删除超链接:
<a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
- 通过vue处理点击事件
<script type="text/javascript">
var vue = new Vue({
el:"#dataTable",
methods:{
//event表示当前事件
deleteEmployee:function (event) {
//通过id获取表单标签
var delete_form = document.getElementById("delete_form");
//将触发事件的超链接的href属性为表单的action属性赋值
delete_form.action = event.target.href;
//提交表单
delete_form.submit();
//阻止超链接的默认跳转行为
event.preventDefault();
}
}
});
</script>
- 控制器方法
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/employee";
}
- 静态资源不会被springMVC处理,所以无法访问vue.js资源,我们需要开放对静态资源的访问,在
springMVC.xml
新增代码:<mvc:default-servlet-handler />
。以后访问静态资源的流程:首先,静态资源会先被springMVC处理,也就是前端控制器DispatcherServlet处理,如果在控制器中找不到相对应的请求映射,就会把静态资源交给默认的servlet来处理,如果默认的servlet能找到相对应的资源,那我们就访问资源,如果找不到相对应的资源,报404
添加
一、点击页面的add
,会实现跳转到添加页面:<th>options(<a th:href="@{/toAdd}">add</a>)</th>
二、因为跳转到添加页面不用做其他处理,所以直接在springMVC.xml
中配置视图控制器:<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
三、创建添加数据的页面employee_add.html
,代码如下:
<body>
<form th:action="@{/employee}" method="post">
lastName:<input type="text" name="lastName"><br>
email:<input type="text" name="email"><br>
gender:<input type="radio" name="gender" value="1">male
<input type="radio" name="gender" value="0">female<br>
<input type="submit" value="add"><br>
</form>
</body>
四、执行保存,控制器中的方法:
@RequestMapping(value = "/employee", method = RequestMethod.POST)
public String addEmployee(Employee employee){
employeeDao.save(employee);
return "redirect:/employee";
}
修改
一、点击页面的update
,会实现跳转到更新数据页面:<a th:href="@{'/employee/'+${employee.id}}">update</a>
,更新数据页面需要回显信息,所以需要取出数据保存在域中,然后在页面从域中取出数据并展示出来
二、查询数据并将数据保存在域中
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET)
public String getEmployeeById(@PathVariable("id") Integer id, Model model){
Employee employee = employeeDao.get(id);
model.addAttribute("employee", employee);
return "employee_update";
}
三、创建更新页面employee_update.html
,在页面中回显数据:
<body>
<form th:action="@{/employee}" method="post">
<input type="hidden" name="_method" value="put">
<input type="hidden" name="id" th:value="${employee.id}">
lastName:<input type="text" name="lastName" th:value="${employee.lastName}">
<br>
email:<input type="text" name="email" th:value="${employee.email}">
<br>
<!--
th:field="${employee.gender}"可用于单选框或复选框的回显
若单选框的value和employee.gender的值一致,则添加checked="checked"属性
-->
gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male
<input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br>
<input type="submit" value="update"><br>
</form>
</body>
四、执行修改:
@RequestMapping(value = "/employee", method = RequestMethod.PUT)
public String updateEmployee(Employee employee){
employeeDao.save(employee);
return "redirect:/employee";
}
处理静态资源的过程
HttpMessageConverter
一、HttpMessageConverter,报文信息转换器,将浏览器发送过来的请求报文转换为Java对象,或将Java对象转换为响应报文,便于浏览器接收
二、HttpMessageConverter提供了两个注解和两个类型:
- @RequestBody:用于将请求报文转换为Java对象
- @ResponseBody:将Java对象转换为响应报文
- RequestEntity:可以接收整个请求报文,既可以接收请求头,又可以接收请求体
- ResponseEntity:加了他之后,可以转换为响应报文
三、新建项目springMVC-demo4
@RequestBody
一、@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody
进行标识,当前请求的请求体就会为当前注解所标识的形参赋值
二、发送请求:
<form th:action="@{/testRequestBody}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit">
</form>
三、服务器接收到请求,请求体会保存在requestBody参数中:
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody){
System.out.println("requestBody:"+requestBody);// requestBody:username=admin&password=123456
return "success";
}
RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()
获取请求头信息,通过getBody()
获取请求体信息
@RequestMapping("/testRequestEntity")
public String testRequestEntity(RequestEntity<String> requestEntity){
System.out.println("requestHeader:"+requestEntity.getHeaders());
System.out.println("requestBody:"+requestEntity.getBody());
return "success";
}
// 输出结果: requestHeader:[host:"localhost:8080", connection:"keep-alive", content-length:"27",cache-control:"max-age=0", sec-ch-ua:"" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"", sec-ch-ua-mobile:"?0", upgrade-insecure-requests:"1", origin:"http://localhost:8080", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/90.0.4430.93 Safari/537.36"] requestBody:username=admin&password=123
HttpServletResponse响应数据
通过控制器处理请求时,对浏览器的请求进行响应有两种方式:响应浏览器一个完整的页面,实现页面跳转,即转发和重定向;响应浏览器数据,以前我们使用HttpServletResponse响应数据:
@RequestMapping("/testResponse")
public void testResponse(HttpServletResponse response) throws IOException {
response.getWriter().print("hello,response");
// print中的内容直接作为响应报文的响应体响应到浏览器中,响应体是什么我们在浏览器中看到的就是什么
}
结果:浏览器页面显示hello,response
@ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
return "success";// 加了@ResponseBody注解,这个success就不再是视图名称了,而是响应体内容
}
结果:浏览器页面显示success
SpringMVC处理json
一、我们上一节响应到浏览器的是个普通字符串,所以可以将响应内容直接在浏览器中展示,如果我响应的是一个对象呢,那么需要将对象转换成JSON对象,然后响应JSON对象,JSON是前后端数据交互的一种格式。新建一个对象src/main/java/com/atguigu/mvc/bean/User.java
:
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String sex;
public User(Integer id, String username, String password, Integer age, String sex) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
}
public User() {}
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
public String getSex() {return sex;}
public void setSex(String sex) {this.sex = sex;}
}
二、@ResponseBody处理json的步骤:
- 在
POM.xml
中导入jackson的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
- 在SpringMVC的核心配置文件
springMVC.xml
中开启mvc的注解驱动:<mvc:annotation-driven />
。此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter
,可以将响应到浏览器的Java对象转换为Json格式的字符串 - 在处理器方法上使用
@ResponseBody
注解进行标识,并将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串
@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser(){
return new User(1001,"admin","1",23,"男");
}
浏览器的页面中展示的结果:{"id":1001,"username":"admin","password":"123456","age":23,"sex":"男"}
SpringMVC处理ajax
一、Ajax的特点:不刷新页面与服务器进行交互,所以不能用转发和重定向,只能用响应浏览器数据
二、点击后发送ajax请求:
<div id="app">
<a th:href="@{/testAjax}" @click="testAjax">testAjax</a><br>
</div>
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
var vue = new Vue({
el:"#app",
methods:{
testAjax:function (event) {
axios({
method:"post",
url:event.target.href,
params:{
username:"admin",
password:"1"
}
}).then(function (response) {
alert(response.data);
});
event.preventDefault();
}
}
});
</script>
三、控制器中的方法
@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "hello,ajax";
}
@RestController注解
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解
ResponseEntity
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
文件上传和下载
下载
使用ResponseEntity实现下载文件的功能:
- 点击页面链接进行下载:
<a th:href="@{/testDown}">下载1.jpg</a><br>
- 映射文件:
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
// ResponseEntity<byte[]>表示响应到浏览器的响应报文
//获取ServletContext对象,ServletContext对象表示我们当前的整个工程
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
// getRealPath()获取当前服务器的部署路径,就是我们这个工程部署到tomcat服务器上的路径
// getRealPath("/static/img/1.jpg")获取文件/static/img/1.jpg在服务器的路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
System.out.println(realPath);
//创建输入流,文件不管上传还是下载,都是一个复制的过程,复制过程:先读再写
InputStream is = new FileInputStream(realPath);
//创建字节数组
// is.available()获取当前输入流所对应的文件的所有字节数
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);// 这行代码执行完毕后,数组中存放的是文件所对应的所有字节,那么我将数组响应到浏览器,就是我要下载的文件
// 将要响应的数据转换成ResponseEntity<byte[]>结构
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字,除了1.jpg是下载的文件名,可以改,其他都是固定写法不能改
// filename=为下载的文件设置的默认名
headers.add("Content-Disposition", "attachment;filename=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
// bytes当前我们要下载的文件的所有字节,即响应体
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
上传
一、在pom.xml中添加依赖:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
二、文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"
。
<!--enctype默认值为:application/x-www-form-urlencoded,表示以key=value&key=value的形式传输数据到服务器
enctype="multipart/form-data"表示以二进制形式传输数据到服务器
-->
<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
头像:<input type="file" name="photo"><br>
<input type="submit" value="上传">
</form>
三、SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息,包括我们要进行的操作和我们要上传的文件。上传的文件不能直接转换成MultipartFile对象,需要在SpringMVC的配置文件springMVC.xml
中配置文件上传解析器,将上传的文件封装为MultipartFile:<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
四、控制器方法如下,为了防止文件重命名,上传的文件保存在服务器中都使用UUID作为文件名
@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
// photo.getName():获取当前表单元素的name属性值
String fileName = photo.getOriginalFilename();//获取上传的文件的文件名
//获取上传的文件的后缀名
// fileName.lastIndexOf("."):获取文件名的后缀名前面的.所在索引
// fileName.substring(索引):截取索引后面的内容并返回
String suffixName = fileName.substring(fileName.lastIndexOf("."));
//将UUID作为文件名
// UUID.randomUUID().toString():随机生成一个UUID
// 生成的UUID有-,replaceAll("-",""):将所有的-都删了
String uuid = UUID.randomUUID().toString().replaceAll("-","");
//将uuid和后缀名拼接后的结果作为最终的文件名
fileName = uuid + suffixName;
//把上传的文件保存到(上传到)服务器中photo目录下,通过ServletContext获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
//判断photoPath所对应路径是否存在
if(!file.exists()){
//若不存在,则创建目录
file.mkdir();
}
// File.separator文件分隔符
String finalPath = photoPath + File.separator + fileName;
//上传文件:photo.transferTo(要上传的地址);
photo.transferTo(new File(finalPath));
return "success";
}