加载静态资源
-
配置Tomcat的默认servlet,即DefaultServlet(注意:该注解要配合开启MVC驱动注解使用才有效)。
-
DefaultServlet的请求路径与DispatcherServlet的请求路径相同,都为 /,
-
处理请求时,开发人员编写的Servlet优先级高于DefaultServlet,因此,当收到客户端传来的请求时,DispatcherServlet先去搜索项目中有无能够处理该请求的方法,若有,则处理请求,若没有,则该请求交给DefaultServlet处理。
-
对于静态资源而言,DispatcherServlet不能处理,需要使用DefaultServlet处理,所以要配置Tomcat的DefaultServlet。
<!-- 配置Tomcat默认Servlet -->
<mvc:default-servlet-handler/>
<!-- 开启MVC驱动 -->
<mvc:annotation-driven/>
Json
小知识
json 有两种格式:
(1)json 对象:{key:value, key:value, ...}
(2)json 数组:[value1, value2, ...]
json 对象的解析方式:对象.key
json 数组的解析方式:for 循环遍历
java 对象转换为 json:
(1)Bean、Map => json 对象
(2)List => json 数组
jackson
当服务器需要向客户端返回 json 格式的数据时,springMVC 默认使用 jackson 将数据转换为 json 格式,再发送给客户端。
springMVC 处理 json 数据的步骤:
- 导入 jackson 的相关 jar 包。
- 在 springMVC 配置文件中开启 MVC 注解驱动。
<mvc:annotation-driven/>
。 - 在处理 json 数据的方法上(常为处理 ajax 请求)使用
@ResponseBody
注解。 - 在方法内,将要以 json 格式发送到客户端的数据以返回值的形式返回。
@ResponseBody
:当方法上添加该注解之后,方法的返回值不再表示视图名称,而是表示要发送给客户端的数据。
代码
springMVC配置文件
<mvc:default-servlet-handler/>
<!-- 开启MVC驱动 -->
<mvc:annotation-driven/>
Student.java
private String stuName;
private Integer gender;
private Integer age;
private School school;
School.java
private String grade;
private String stuClass;
TestJson.java
@Controller
public class TestJson {
@RequestMapping(value="/stuInfo",method=RequestMethod.GET)
@ResponseBody
public List<Student> getStuInfo() {
Student stu1 = new Student("MCC1", 1, 20, new School("p1", "jlu1"));
Student stu2 = new Student("MCC2", 0, 21, new School("p2", "jlu2"));
Student stu3 = new Student("MCC3", 1, 22, new School("p3", "jlu3"));
ArrayList<Student> stuList = new ArrayList<Student>();
stuList.add(stu1);
stuList.add(stu2);
stuList.add(stu3);
return stuList;
}
}
json.jsp
- 实现1:遍历输出返回的 json 数组(因为服务器返回的是 List 集合,因此被转换为 json 数组)。
- 实现2:不刷新页面,将数据以列表形式显示。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>json</title>
<script type="text/javascript" src="${ pageContext.request.contextPath }/static/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function(){
$("#ajax1").click(function(){
$.ajax({
url:"http://localhost:8080/RESTful_CRUD/stuInfo",
type:"Get",
success:function(msg){
//实现1:遍历输出返回的json数组(因为服务器返回的是List集合,因此被转换为json数组)
/*
for(var i=0;i<msg.length;i++){
alert("stuName:"+msg[i].stuName+", school:"+msg[i].school.grade);
}
*/
//实现2:不刷新页面,将数据以列表形式显示
var stuTable =
"<table>"+
"<tr>"+
"<th>姓名</th>"+
"<th>性别</th>"+
"<th>年龄</th>"+
"<th>年级</th>"+
"<th>班级</th>"+
"</tr>";
for(var i=0; i<msg.length; i++){
stuTable +=
"<tr>"+
"<td>"+msg[i].stuName+"</td>"+
"<td>"+msg[i].gender+"</td>"+
"<td>"+msg[i].age+"</td>"+
"<td>"+msg[i].school.grade+"</td>"+
"<td>"+msg[i].school.stuClass+"</td>"+
"</tr>";
}
stuTable += "</table>";
$("body").append(stuTable);
},
dataType:"json"
});
});
//测试使用$.getJSON()
$("#ajax2").click(function(){
$.getJSON("http://localhost:8080/RESTful_CRUD/stuInfo",function(msg){
for(var i=0;i<msg.length;i++){
alert("stuName:"+msg[i].stuName+", school:"+msg[i].school.grade);
}
});
});
});
</script>
</head>
<body>
<button id="ajax1">ajax1</button>
<button id="ajax2">ajax2</button>
</body>
</html>
文件上传与下载
文件上传
springMVC 将上传的文件转换为 MultipartFile
类型,该类型需要在 springMVC 配置文件中进行配置才能使用。
注意:
(1)bean 标签的 id 值为固定值id="multipartResolver"
,不能修改。
(2)可以通过 property 标签设置上传对象的属性,如默认编码格式defaultEncoding
、最大上传文件大小maxUploadSize
等。
<!-- 处理文件,将上传的File文件转换为MultipartFile -->
<!-- 注意:id为固定名称,不能修改 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的编码格式,一定要和jsp页面的pageEncoding值保持一致 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设置最大上传文件大小,大小要写具体的数字,不能写表达式 -->
<property name="maxUploadSize" value="10240000"></property>
</bean>
方法 | 作用 |
---|---|
getName() | 获取表单 type=“file” 输入框的 name 属性值 |
getOriginalFilename() | 获取上传文件的文件名 |
getInputStream() | 获取上传文件的输入流 |
transferTo() | 读取文件输入流,写入到磁盘输出流 |
-
上传单个文件
实现方式:在方法的参数位置传入 MultipartFile 对象。
注意:对象名要与表单的 name 属性值相同。<form action="http://localhost:8080/RESTful_CRUD/upload" method="post" enctype="multipart/form-data"> 文件:<input type="file" name="file"/><br/> 描述:<input type="text" name="description"/><br/> <input type="submit" value="上传"/> </form>
方法1:使用 getInputStream()(麻烦)
/** * 单文件上传 * @param file * @param decription * @return * @throws IOException */ @RequestMapping(value="/upload",method=RequestMethod.POST) public String fileUpload_old(MultipartFile file, String decription, HttpSession session) throws IOException { //获取type="file"输入框的name属性值 //String name = file.getName(); //System.out.println(name);//file //获取上传文件的文件名 String filename = file.getOriginalFilename(); //System.out.println(filename);//1577368025905.jpg //获取上传文件的输入流 InputStream inputStream = file.getInputStream(); //将上传的文件保存到upload文件夹下 //获取upload文件夹的磁盘路径 String path = session.getServletContext().getRealPath("upload"); String finalPath = path + File.separator + filename; OutputStream outputStream = new FileOutputStream(new File(finalPath)); //读取文件,并写入到输出流 byte[] b = new byte[1024]; int i = 0; while((i=inputStream.read(b))!=-1) { outputStream.write(b, 0, i); } inputStream.close(); outputStream.close(); return "success"; }
方法2:使用 transferTo()(常用)
/** * 单文件上传 * @param file * @param decription * @return * @throws IOException */ @RequestMapping(value="/upload",method=RequestMethod.POST) public String fileUpload(MultipartFile file, String decription, HttpSession session) throws IOException { //获取文件名 String filename = file.getOriginalFilename(); //将文件保存到upload文件夹下,获取文件夹路径 String path = session.getServletContext().getRealPath("upload"); //通过UUID设置文件名,避免文件重名 //格式为:upload/filenameUUID.xxx`在这里插入代码片` //以filename的最后一个.为分隔符,将文件名分割,再与UUID拼接 String prefix = filename.substring(0, filename.lastIndexOf(".")); String suffix = filename.substring(filename.lastIndexOf(".")); //与UUID拼接 String finalPath = path + File.separator + prefix + UUID.randomUUID() + suffix; //读取文件输入流,写入到磁盘输出流 file.transferTo(new File(finalPath)); return "success"; }
-
上传多个文件
实现方式:在方法的参数位置传入 MultipartFile[ ] 对象
注意:对象名要与表单的 name 属性值相同。<!-- 上传多个文件 --> <form action="http://localhost:8080/RESTful_CRUD/uploadMore" method="post" enctype="multipart/form-data"> 文件:<input type="file" name="files"/><br/> 文件:<input type="file" name="files"/><br/> 描述:<input type="text" name="description"/><br/> <input type="submit" value="上传"/> </form>
/** * 多文件上传 * @param file * @param decription * @return * @throws IOException */ @RequestMapping(value="/uploadMore",method=RequestMethod.POST) public String fileUploadMore(MultipartFile[] files, String decription, HttpSession session) throws IOException { for(int i=0; i<files.length; i++) { MultipartFile file = files[i]; //获取文件名 String filename = file.getOriginalFilename(); //将文件保存到upload文件夹下,获取文件夹路径 String path = session.getServletContext().getRealPath("upload"); //通过UUID设置文件名,避免文件重名 //格式为:upload/filenameUUID.xxx //以filename的最后一个.为分隔符,将文件名分割,再与UUID拼接 String prefix = filename.substring(0, filename.lastIndexOf(".")); String suffix = filename.substring(filename.lastIndexOf(".")); //与UUID拼接 String finalPath = path + File.separator + prefix + UUID.randomUUID() + suffix; //读取文件输入流,写入到磁盘输出流 file.transferTo(new File(finalPath)); } return "success"; }
文件下载
ResponseEntity<T>
:响应实体类,springMVC 通过返回该类对象,实现下载功能。new ResponseEntity<T>(byte[] body,MultiValueMap<String, String> headers,HttpStatus status)
:构造方法内需要传入三个参数。getRealPath()
:参数为空字符串时,返回项目在磁盘上的绝对路径;参数为文件名时,返回文件在磁盘上的绝对路径。
<a href="http://localhost:8080/RESTful_CRUD/download/1577368025905.jpg">下载1577368025905.jpg</a>
/**
* 文件下载
* @param fileName
* @param session
* @return 下载实体 ResponseEntity<byte[]>
* @throws IOException
*/
@RequestMapping("/download/{fileName}")
public ResponseEntity<byte[]> fileDownload(@PathVariable("fileName")String fileName, HttpSession session) throws IOException{
//获取文件路径
//getRealPath():参数为空字符串时,返回项目在磁盘上的绝对路径;参数为文件名时,返回文件在磁盘上的绝对路径
String path = session.getServletContext().getRealPath("imgs");
String realPath = path + File.separator + fileName + ".jpg";
//读取文件
FileInputStream inputStream = new FileInputStream(new File(realPath));
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
byte[] b = new byte[bufferedInputStream.available()];
//设置响应头
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename="+fileName);
//设置响应状态码
HttpStatus httpStatus = HttpStatus.OK;
ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(b, headers, httpStatus);
return entity;
}
拦截器
概念
拦截器的作用位置:拦截器作用在 springMVC 核心控制器将请求分发到对应的 Servlet 程序之间的位置。
自定义拦截器
- springMVC 提供了一个默认拦截器,程序员可以通过如下两种方式实现自定义拦截器:
(1)实现HandlerInterceptor接口
(2)继承HandlerInterceptorAdapter适配器类
- HandlerInterceptor 接口内有三个方法:
(1)preHandle()
:在 Servlet 程序执行之前执行。若返回 true,则继续执行 Servlet 程序,若返回 false,则结束 Servlet 程序。
(2)postHandle
:在 Servlet 程序处理完请求之后,但 DispatcherServlet 向客户端返回响应数据之前执行。
(3)afterCompletion()
:在 Servlet 程序执行完毕后执行。若 preHandle() 返回 true,且该拦截器前没有返回 false 的拦截器,则该方法一定会执行,若 preHandle 返回 false,则该方法一定不会执行。即:返回 false 的拦截器之前的所有返回 true 的拦截器的 afterCompletion() 方法都会执行。 - 在springMVC 的配置文件中,使用标签
<mvc:interceptors></mvc:interceptors>
配置拦截器类。配置方法:
(1)通过 bean 标签的 class 属性,设置某个类为拦截器类。
(2)在拦截器类上使用注解 @Component 创建对象,在 ref 标签内通过 bean 属性指定该类为拦截器类。
<mvc:interceptors>
<!-- 将MyInterceptor类设置为拦截器类 -->
<bean class="com.mcc.springMVC.interceptor.MyInterceptor"></bean>
<!-- <ref bean="myInterceptor"/> -->
</mvc:interceptors>
package com.mcc.springMVC.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@Component
public class MyInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// TODO Auto-generated method stub
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
super.afterCompletion(request, response, handler, ex);
}
}
设置拦截路径
不设置拦截路径时,拦截器默认拦截全部请求,拦截路径以/
开始。
方法:使用<mvc:interceptor></mvc:interceptor>
标签实现。
在该标签内,有属性:
(1)<mvc:mapping path=""/>
:拦截路径,如:拦截所有请求路径为 .html 的请求<mvc:mapping path="/*.html"/>
(2)<bean></bean>
:为哪个拦截器设置拦截路径
(3)<mvc:exclude-mapping path=""/>
:不需要拦截的路径
多个拦截器的执行顺序
当有多个拦截器时,有以下几种情况:(以下假设除 springMVC 默认拦截器外,还有两个自定义拦截器)
拦截器 | preHandle() 的返回值 | 执行顺序 |
---|---|---|
1,2 | 1:true,2:true | 1:preHandle() => 2:preHandle() => 2:postHandle() => 1:postHandle() => 2:afterCompletion() => 1:afterCompletion() |
1,2 | 1:true,2:false | 1:preHandle() => 2:preHandle() => 1:afterCompletion(),返回 false 的拦截器之前的所有返回 true 的拦截器的 afterCompletion() 方法都会执行。 |
1,2 | 1:false,2:true | 1:preHandle() |
1,2 | 1:false,2:false | 1:preHandle() |