SpringMVC学习总结
使用步骤:
1、创建web项目
2、编写web.xml,在其中注册一个特殊的servlet,前端控制器
3、编写一个springmvc的配置文件
1、注册一个视图解析器
4、编写控制器
5、编写一个结果页面
依赖
web.xml
javax.servlet
javax.servlet-api
3.1.0
provided
javax
javaee-api
7.0
org.springframework
spring-webmvc
5.0.8.RELEASE
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
标签配置开发模式(方法一:不推荐使用)
springmvc-servlet.xml
springmvc的配置文件,对每一个springmvc控制器都需要配置bean标签
HelloController.java
控制器
xmlns=“http://xmlns.jcp.org/xml/ns/javaee”
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id=“WebApp_ID” version=“3.1”>
springmvc
org.springframework.web.servlet.DispatcherServlet
springmvc
/
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
package cn.cxhi.controller;
hello.jsp
视图代码
SpringMVC分析
组件分析
web.xml
注册前端控制器,目的在于,我们希望让springmvc去处理所有的请求
通过
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//实现一个Controller接口的方式
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject(“hello”,“Hello World!”);//传递到视图的参数
modelAndView.setViewName(“hello”);//视图名称
return modelAndView;
}
}
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
Happy New Year:${hello}
springmvc
/
上面配置springMvc去所有的请求
url-pattern的写法问题
关于前端控制器的解释
springmvc设计的理念是希望开发者尽量远离原生的servletAPI,API不是很好用,有些繁琐,将操作进一步的简化,
他将很多东西责任进行了拆分,不希望我们将一些技术点绑定死,可以做到随意的切换。本身还是基于servlet设计
的,分发的servlet, springmvc配置文件名字的问题
默认情况下是dispatcherServlet的名字当做命名空间
[ServletName]-servlet.xml (WEB-INF)
servletName-servlet.xml = namespace.xml
之下寻找
降配置文件移动位置之后,出现了相应的错误
如果非要重新使用另外一个名字,可以使用
默认的规则要求在web-inf下,但是maven项目的标准应该在resources下面,解决方案:
重新指定上下文的配置文件的位置即可
/ =>(推荐使用)
处理所有的请求,但是和/*不一样,他处理完之后要出去的时候不会再去将这个hello.jsp当做一个新的请求,而是
将这个渲染的结构直接返回给浏览器
/* =>(永远都不要这么写)
不能写的原因:请求/helloController过去的时候,他的视图名称是hello,hello.jsp页面,他将其当做了一个
叫hello.jsp的请求,尝试去匹配对应的Controller,但是我的容器当中根本不存在这样的controller,所以无法匹
配,导致404
*.do
这种方式,有的开发团队习惯将请求的行为加个小尾巴用以区分,.do,.action
namespace
mvc
contextConfigLocation
classpath:springmvc-servlet.xml
视图解析器
springmvc支持多种视图技术
jsp
freemaker
内部的资源视图解析器
视图前缀
/jsp/他是我们的请求相应的资源的路径的配置, viewName:hello /jsp/hello
视图后缀
.jsp 此时我们的前缀+视图名称+后缀 =/jsp/hello.jsp
解析器的作用类似于
request.getDispatcherServlet.forward(request,response);
物理视图是由逻辑视图转换而来
物理视图是webapp/jsp/hello.jsp
逻辑视图 p View =prefix + logicViewName + suffix
prefix => 前缀
logicViewName =>视图名称(在Controller中的ModelAndView的setViewName()方法来指定)
suffix =>后缀
控制器
是一种比较传统的实现一个接口的方式完成的,Controller
如果一个接口只有一个方法,这种接口叫做函数式接口
ModelAndView方法是Controller接口内的唯一的一个方法,故Controller为函数式接口
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse) throws Exception {
}
该代码类似于servlet里面由doGet doPost里面入参就是请求与相应。
在springmvc中,在model当中填充数据,然后在具体的视图进行展示
还需要在配置文件当中配置一下bean,这个bean要取个名字,就用来充当这个URI,他就处理一个请求,跟servlet
的差别不是很大。
注解开发模式(方法二:推荐使用)
基于实现接口的方式已经是过去式了,采用注解开发很简单 基本注解
@Controller
@RequestMapping
可以写在方法上
也可以写在类上
推荐使用二者结合的方式
组合使用实例
@Controller
@RequestMapping("/bye")
public class ByeController {
//要想访问该Controller具体的地址应该是"http://localhost:8080/bye/bye"
@RequestMapping("/bye")
public String bye(Model model){
model.addAttribute(“hello”,“我的世界”);
//返回的为viewName,即视图的名字,此时寻找视图的路径为 /jsp/hello.jsp
return “hello”;
}
}
使用联合方式,第一个/bye可以区分大类,第二个/bye直接调用该具体Controller
springmvc-servlet.xml
需要添加相应的命名空间,以使用Context
<context:component-scan base-package=“cn.cxh.controller” />
Controller.java
package cn.cxh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//使用注解需要在springmvc的配置文件里面导入一个包,以启动注解扫描
//不需要继承任何的类也不需要实现任何的接口
@Controller
public class ByeController {
@RequestMapping
public String bye(Model model){
//往view层传值
model.addAttribute(“hello”,“我的世界”);
//返回的为viewName,即视图的名字,此时寻找视图的路径为 /jsp/hello.jsp
return “hello”;
}
}
注解开发步骤总结:
1、配置基础扫描的包,这样配置的注解才会生效
2、在指定的类上面添加@Controller注解
3、在Controller类的方法前添加@RequestMapping注解,类似于前面的Controller的那个名字(不同
requesthandler处理的handlerMapping)
当我们写上Controller之后,就标记了它为spring的一个组件,并且是控制器的组件,此时我们的handlermapping
会去扫描寻找这个controller是否与之匹配,如果发现匹配就把这里处理的工作交给它
匹配的规则:
具体的匹配就是通过请求的路径进行匹配的
@RequestMapping(URI)
此时就是通过这个URI进行匹配
转发与重定向
转发
//请求
@RequestMapping("/forward")
public String forward(Model model){
//springmvc model默认是在请求域中存储值
System.out.println(“请求”);
model.addAttribute(“skill”,“请求测试”);
return “forward”;
}
重定向
//重定向
@RequestMapping("/redirect")
public String redirect(Model model){
model.addAttribute(“skill”,“重定向测试”);
System.out.println(“重定向”);
//重定向是需要在return的内容中增加重定向的标识=>“redirect:”+重定向视图的路径
return “redirect:/jsp/redirect.jsp”;
}
转发到页面 (默认)
重定向到页面 redirect:path
转发到另外一个控制器 forward:path
关于springmvc访问web元素
request
session
application
可以通过模拟的对象完成操作,也可以使用原生的servletAPI完成,直接在方法当中入参即可
package cn.cxh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.WebRequest;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/web")
public class WebElementController {
//request元素
@RequestMapping(“request”)
public String request(WebRequest request){
System.out.println(request.getParameter(“test”));
return “forward”;
}
//session元素
@RequestMapping(“session”)
public String session(HttpSession session){
session.setAttribute(“test”,“我是张三”);
return “forward”;
}
//application元素
@RequestMapping(“application”)
public String application(HttpSession session){
//获取application并设置test
session.getServletContext().setAttribute(“application”,“application测试”);
return “redirect:/jsp/forward.jsp”;
}
}
注解详解
@RequestMapping
value 写的是路径,是一个数组的形式,可以匹配多个路径
path 是value的别名,所以二者人选其一,他们的作用是一样的
method 指定可以访问的请求的类型,比如post,get,他也可以写成一个数组的形式
params 可以指定参数,还可以去限定这个参数的特征,比如等于某个值
params={“girl=a”,“boy!=b”} =>当请求的参数girl等于a,boy不等于b的时候才能继续向下执行
headers 能够影响浏览器的行为
consumers 消费者,媒体类型,可以限定为application.json;charset=UTF-8
produces 产生的响应的类型
//请求映射的路径path可以有多个值,即请求这个controller可以用多个名字,m1,m2都可以请求这个
Controller
// @RequestMapping(value = {"/m1","/m2"})
// @RequestMapping(path = {"/m1","/m2"})
//该请求只能接受post提交的表单
@RequestMapping(path = {"/m1","/m2"},method = RequestMethod.POST)
public String m1(Model model){
model.addAttribute(“annotations”,"@RequestMapping注解");
return “annotations”;
}
//用以处理get请求,参数为两个,分别为a和b
@RequestMapping(path = “/m2”,method = RequestMethod.GET,params = {“a”,“b”})
public String m2(@RequestParam(“a”)Integer a, @RequestParam(“b”) Integer b){
System.out.println(a+b);
return “annotations”;
}
@GetMapping,@PostMapping…
相等于RequestMapping中的method指定为get或者post,只能相应处理get或者post请求
@PathVariable
resultful风格
请求时的url可以写成=》/product/add/产品id/产品名称/产品价格
该Controller可以自动接收通过url传入的参数
@Controller
@RequestMapping("/product")
public class ProductController {
@RequestMapping("/add/{id}/{name}/{price}")
public String addProduct(@PathVariable(“id”)Integer id,@PathVariable(“name”)String
name,@PathVariable(“price”)Double price){
System.out.println(id+name+price);
return “forward”;
}
}
对于非get,post请求的支持
对于非get,post请求的支持,需要有额外的内容添加,要增加一个过滤器来额外处理
他返回的不是页面,而是数据
DeleteMapping
PutMapping
过滤器
过滤器使用
hiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter</filterclass>
hiddenHttpMethodFilter
/*
表单提交里面还要添加一个隐藏的参数
@PutMapping
关于获取项目名称的问题
@WebServlet(urlPatterns = {},loadOnStartup = 2)
public class WebPathInitServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
//在整体应用上下文当中存储了一个ctx的值,用他来引用上下文路径
config.getServletContext().setAttribute(“ctx”,config.getServletContext().getContextPath(
));
super.init(config);
}
}
在jsp页面中需要全局项目名称时只需要引用${ctx},在此后的访问静态资源时会使用
关于请求路径的问题
springmvc支持ant风格
?任意的字符
“*” 0到n,任意个字符都可以,/除外
** 支持任意层路径,
// 访问地址可以写为"/test/m3"+“任意单个字符,/除外”
// @RequestMapping(path = “/m3?”)
// 访问地址可以写为"/test/m3"+“可以放任意长度的字符串,但是不能包括/”
// @RequestMapping(path = “m3*”)
// 访问地址可以写为"/m3"+"/a"+"/b",可以有多层路径
@RequestMapping(path = “m3/**”)
public String m3(){
System.out.println(“m3…”);
return “annotations”;
}
关于静态资源访问的问题
由于我们的servlet设置了URL匹配方式为/,所以,他将静态资源也当做一个后台的请求,
比如http://localhost:8080/SpringMVC/static/css/index.css
他尝试去匹配一个static/css/index.css的Controller里面的requestMapping的组合,因为没有,所以404,解决方式
很多,最简单的,是让springmvc单独处理,将这些交给容器的默认的servlet处理,就不让DispatcherServlet来处
理了
解决方式一(推荐使用这种方式,当需要引用的文件不能被识别时,可以增加第二种方式来引入)
<mvc:default-servlet-handler />
<mvc:annotation-driven />
解决方式二
<mvc:resources mapping=“static/css/*” location=“static/css/” />
关于post请求中文乱码问题的解决
添加一个过滤器即可,springmvc提供了非常好的字符编码过滤器,所以我们注册即可
在web.xml中添加这样的配置进行注册(最好是放在servlet过滤器之前)
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceRequestEncoding
true
characterEncodingFilter
/*
关于form表单提交数据的方式
方式一 通过属性名绑定
通过属性名称进行绑定,可以完成数据绑定
页面当中表单元素的name值要和后台的形参的名字保持一致。
如果有多个,多个形参按名字绑定即可,当传入的值校对的时候,会比较麻烦
控制器
@PutMapping(“put”)
@ResponseBody
//形参要与前台页面传过来的name名称相对应
public String put(String name){
System.out.println(name);
return “@PutMapping测试成功”;
}
方式二 利用@RequestParam注解
jsp页面不变
控制器
@PutMapping(“put”)
@ResponseBody
public String put1(@RequestParam(“name”) String name){
System.out.println(name);
return “@PutMapping测试成功”;
}
方式三 直接使用pojo形式传递
控制器
@PutMapping("/put2")
@ResponseBody
public String put2(User user){
System.out.println(user.getName()+user.getPassword());
return “@PutMapping测试成功”;
}
关于form表单提交日期格式数据问题的处理
1、处理日期(没有时间)
@InitBinder(“user”)
public void init(WebDataBinder webDataBinder){
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy-MM-dd”);
sdf.setLenient(false);
webDataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,false));
}
@PostMapping("/model3")
public String model3(@ModelAttribute(“user”) User user){
System.out.println(user.getName()+user.getPassword());
System.out.println(user.getBirth());
return “msg”;
}
//通过initBinder指定了user名字和modelAttribute里面的user绑定
2、不指定名字,根据数据类型一样可以分析解析转换成功
@InitBinder()
public void init(WebDataBinder webDataBinder){
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy-MM-dd”);
sdf.setLenient(false);
webDataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,false));
}
@PostMapping("/model3")
public String model3(@ModelAttribute() User user){
System.out.println(user.getName()+user.getPassword());
System.out.println(user.getBirth());
return “msg”;
}
3、时间+日期的处理(推荐使用注解方式)
//通过Java源码的方式(如1、2),解决方案不是很理想,只能处理固定格式的时间日期格式,个人建议使用注解的方式来解
决比较好
@DateTimeFormat(pattern = “yyyy-MM-dd”)
private Date birth;
注解补充
@ResponseBody
返回数据,一般情况下返回json格式,需要引用json包
put.jsp =>put请求方式为例
UserController.java
@Controller
@RequestMapping("/user")
public class UserController {
//相应put请求
@PutMapping(“put”)
//表示将返回一个数据结果,而不是页面
@ResponseBody
public String put(String name){
System.out.println(name);
//返回数据,为测试方便,结果返回一个String字符串
return “@PutMapping测试成功”;
}
}
@ModelAttribute
使用方式一:
//就是在controller里面的任意一个处理具体的方法之前执行
@ModelAttribute
public User init(){
User u=new User();
u.setName(“李四”);
return u;
}
@RequestMapping("/model")
public String model(Model model){
//判断init()方法是否在该方法之前执行,即判断init()方法是否返回了User对象,同时确定了
init()返回的对象名是什么
System.out.println(model.containsAttribute(“user”));
System.out.println(model.addAttribute(“user”));
return “msg”;
}
如果某些对象从头到尾每次请求当中都要存在,不消失,就适合使用这种方法。
使用方式二
//就是在controller里面的任意一个处理具体的方法之前执行
@ModelAttribute
public void init(Model model){
User u=new User();
u.setName(“李四”);
model.addAttribute(“user”,u);
}
@RequestMapping("/model")
public String model(Model model){
//判断init()方法是否在该方法之前执行,即判断init()方法是否返回了User对象,同时确定了init()返回的
对象名是什么
System.out.println(model.containsAttribute(“user”));
System.out.println(model.addAttribute(“user”));
return “msg”;
}
使用方式三:
//如果前台没有传过来相应的值,使用该注解后会自动去我们的model模型中寻找相应的user,
//如果前台传值过来,则init()方法返回的内容则由前台穿过来的model模型替换
@RequestMapping("/model2")
public String model2(@ModelAttribute User user){
System.out.println(user.getName()+user.getPassword());
return “msg”;
}
@InitBinder
@DateTimeFormat
用以标记处理springmvc的中传值时间日期问题,格式化时间日期
@DateTimeFormat(pattern = “yyyy-MM-dd”)
private Date birth;
@RequestBody
json数据,不是通过form表单传递
ajax({
data:
})
@SessionAttributes
@Controller
@RequestMapping("/user3")
@SessionAttributes(“user”)
public class User3Controller {
@PostMapping("/session")
public String session(User user){
return “redirect:/jsp/user.jsp”;
}
}
@SessionAttribute
要求当前这次访问当中的会话当中必须有某个对象,简而言之,@SessionAttributes是往会话中添加某个模型数据,
而@SessionAttribute是为了检查当前会话中是否有需要检测的模型数据
@RestController
@RestController=@Controller+@ResponseBody
该注解标记的Controller类可以指定该Controller类中的所有方法都返回数据,而不是返回页面
JSON数据交互
添加相关依赖
org.codehaus.jackson
jackson-mapper-asl
1.9.13
com.fasterxml.jackson.core
jackson-core
2.8.0
com.fasterxml.jackson.core
jackson-databind
2.8.0
JSON如何返回前台
1、返回一个pojo
//返回一个pojo
@RequestMapping("/m1")
@ResponseBody //这个注解将制定返回的不是视图,而是数据,他会将我们的返回数据格式转换为json数据格式
public User json1(){
User user=new User();
user.setName(“李四”);
user.setPassword(“root”);
return user;
}
2、返回一个Map
//返回一个Map
@RequestMapping("/m2")
@ResponseBody //这个注解将制定返回的不是视图,而是数据,他会将我们的返回数据格式转换为json数据格式
public Map<String,Object> json2(){
Map<String,Object> map=new HashMap<>();
map.put(“name”,“张三”);
map.put(“age”,21);
return map;
}
3、返回一个数组
@RequestMapping("/m3")
@ResponseBody
public User[] json3(){
User user1=new User();
user1.setName(“李四1”);
user1.setPassword(“123”);
User user2=new User();
user2.setName(“李四2”);
user2.setPassword(“456”);
return new User[]{user1,user2};
}
4、返回一个list
@RequestMapping("/m4")
@ResponseBody
public List json4(){
List list=new ArrayList<>();
User user1=new User();
user1.setName(“我是你爸爸”);
user1.setPassword(“你爸爸”);
User user2=new User();
user2.setName(“你爸爸就是你爸爸”);
user2.setPassword(“你就是你”);
list.add(user1);
list.add(user2);
return list;
}
JSON如何在前台解析
1、解析返回的pojo
$.ajax({
url:’${ctx}/json/m1’,
type:‘post’,
success:function (data) {
alert(data.name);
alert(data.password);
}
})
2、解析返回的map
//接收返回的map
$(’#map’).click(function () {
$.ajax({
url:’${ctx}/json/m2’,
type:‘post’,
success:function (data) {
alert(data.name);
alert(data.age);
}
})
})
3、解析返回的数组
//接收返回的数组
$(’#array’).click(function () {
$.ajax({
url:’${ctx}/json/m3’,
type:‘post’,
success:function (data) {
for(var i=0;i<data.length;i++){
alert(data[i].name);
alert(data[i].password);
}
}
})
})
4、解析返回的list
//接收返回的数组
$(’#list’).click(function () {
$.ajax({
url:’${ctx}/json/m4’,
type:‘post’,
success:function (data) {
for(var i=0;i<data.length;i++){
alert(data[i].name);
alert(data[i].password);
}
}
})
})
JSON如何将数据传到后台
必须要添加,来规范传输json数据格式以及编码标准
contentType:“application/json;charset=utf-8”
1、前台ajax向后台发送一个pojo
$(’#user’).click(function () {
var obj={
“name”:“李四”,
“password”:“123”
};
$.ajax({
url:’${ctx}/json2/add’,
type:‘post’,
contentType:‘application/json’,
data:JSON.stringify(obj),
success:function (data) {
}
})
})
2、前台ajax向后台发送一组pojo
$(’#userList’).click(function () {
var obj={
“name”:“李四”,
“password”:“456”
};
var obj2={
“name”:“李四1”,
“password”:“123”
};
var array=new Array();
array.push(obj);
array.push(obj2);
$.ajax({
url:’${ctx}/json2/addList’,
type:‘post’,
contentType:‘application/json’,
data:JSON.stringify(array),
success:function (data) {
if(data.code==2000){
alert(“测试成功”);
}
}
})
})
//前台提交一个user过来
@RequestMapping("/addList")
//User user入参只能处理form表单提交的数据
//要想接收前台ajax发过来的json数据,需在入参时添加@RequestBody注解
@ResponseBody
public Map<String,Integer> addList(@RequestBody List user){
Map<String,Integer> map=new HashMap<>();
map.put(“code”,2000);
System.out.println(user);
return map;
}
XML数据交互
对于很多第三方开发,还是有很多会采用xml作为数据交互,比如微信
添加额外依赖
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
2.9.3
a
方法测试
自作了解,需要用时自行查阅资料百度
//produces用于指定返回数据的数据类型,在这里我们指定为XML格式
@RequestMapping(value = “/m1”,produces = MediaType.APPLICATION_ATOM_XML_VALUE)
@ResponseBody
public User m1(){
User user=new User();
user.setName(“李四”);
user.setPassword(“123”);
return user;
}
文件上传与下载
文件上传
方式一:Apache Upload文件上传方式
1、添加相关依赖
commons-fileupload
commons-fileupload
1.3.3
2、在springmvc的配置文件中注册一个文件上传解析器
<bean id=“multipartResolver”
class=“org.springframework.web.multipart.commons.CommonsMultipartResolver”>
3、准备一个上传的页面
<%–要实现文件上传,必须要添加enctype=“multipart/form-data”
是将文件以二进制的形式上传,这样可以实现多种类型的文件上传
–%>
文件:
4、后台处理程序
@Controller
@RequestMapping("/file")
public class FileController {
private static String uploadPath=“I:/newFile/”;
/**
- 文件上传要处理的问题
- 1、传到哪里去;2、要传什么东西;3、文件传输的细节
- @param multipartFile
- @return
/
@RequestMapping("/upload")
public String upload(@RequestParam(“upload”)MultipartFile multipartFile, Model model){
//1、判断上传的文件是否为空
if(multipartFile!=null && !multipartFile.isEmpty()){
//2、获取上传文件的原始文件名
String originalFilename = multipartFile.getOriginalFilename();
//3、截取源文件名的前缀,不带后缀
String
fileNamePrefix=originalFilename.substring(0,originalFilename.lastIndexOf("."));
//4、加工处理原文件名,原文件名+时间戳
String newFileNameProfix=fileNamePrefix+new Date().getTime();
//5、得到新的文件名
String
newFileName=newFileNameProfix+originalFilename.substring(originalFilename.lastIndexOf("."));
//6、构建文件对象
File file =new File(uploadPath+newFileName);
//7、上传
try {
multipartFile.transferTo(file);
model.addAttribute(“fileName”,newFileName);
} catch (IOException e) {
e.printStackTrace();
}
}
return “success”;
}
}
文件下载
@Controller
@RequestMapping("/download")
public class DownloadController {
//定义一个文件下载的路径
private static String DownloadPath=“I:/newFile/”;
//
@RequestMapping("/down")
public String download(HttpServletResponse response){
//通过输出流写入到客户端
//1、获取文件下载名
String fileName=“typora-setup-x64.exe”;
//2、构建一个文件对象通过Paths工具类获取一个Path对象
Path path = Paths.get(DownloadPath, fileName);
//3、判断文件是否存在
if(Files.exists(path)){
//存在则此下载
//通过response设定它响应的类型
//4、获取文件的后缀,即获取文件的类型
String fileSuffix=fileName.substring(fileName.lastIndexOf(".")+1);
//5、设置contentType,只有指定他才能下载文件
response.setContentType(“application/”+fileSuffix);
//6、添加头信息
//因为是springmvc只能处理ISO8859-1,所以要将文件名通过UTF-8提取出字节流名称再转换成标
准的ISO8859-1
try {
response.setHeader(“Content-Disposition”,“attachment;filename=”+new
String(fileName.getBytes(“UTF-8”),“ISO8859-1”));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//7、通过path写出该文件
try {
Files.copy(path,response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
return “success”;
}
}
拦截器
springmvc提供了拦截器,类似于过滤器,他将在我们的请求距离之前先做检查,有权决定,接下来是否继续,对我
们的请求进行加工。拦截器,可以设计多个,
通过实现HandlerIntercepror,这是一个接口,定义了三个非常重要的方法
前置处理
后置处理
完成处理
案例一,运行时间计算与好坏判断
后台代码
package cn.cxh.interceptors;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/* - 方法耗时统计的拦截器
*/
public class MethodTimerInterceptor implements HandlerInterceptor {
private static final Logger LOGGER=Logger.getLogger(MethodTimerInterceptor.class);
//前置功能 开始到结束,计算两个点之间所需要的时间
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
//1、定义开始时间
配置文件
案例二:Session拦截器
后台代码
long start=System.currentTimeMillis();
//2、将开始时间存到请求域当中
request.setAttribute(“start”,start);
//记录请求日志
LOGGER.info(request.getRequestURI()+“请求到达!”);
//返回true,才会去找下一个拦截器,如果没有下一个拦截器,则去到Controller执行请求
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object
handler, ModelAndView modelAndView) throws Exception {
//1、得到开始的时间
long start= (long) request.getAttribute(“start”);
//2、得到结束的时间
long end=System.currentTimeMillis();
//3、计算耗时
long speedTime=end-start;
if(speedTime>=1000){
LOGGER.warn(“请求耗时严重,耗时:”+speedTime+“毫秒”);
}else{
LOGGER.info(“请求耗时正常,耗时:”+speedTime+“毫秒”);
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}
mvc:interceptor <mvc:mapping path="/*/"/>
/mvc:interceptor
package cn.cxh.interceptors;
import cn.cxh.entity.User;
import org.apache.log4j.Logger;
配置文件
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** - 会话拦截器
*/
public class SessionInterceptor implements HandlerInterceptor {
private static final Logger LOGGER=Logger.getLogger(SessionInterceptor.class);
//检查当前会话是不是有该User,如果有,放行,如果没有,则拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
//获取会话中的User对象
Object user=request.getSession().getAttribute(“SESSION_USER”);
//判断该用户是否登录,
if(user == null){
LOGGER.warn(“您不具备该权限,请先登录”);
return false;
}
//先判断user是否为空,即判断用户是不是登录
//如果用户登录,则判断用户是不是User类型
if(user instanceof User){
//去数据库检测该用户是否存在,给予该用户冻结状态,密码附空
User u= (User) user;
u.setPassword(null);
request.getSession().setAttribute(“SESSION_USER”,u);
LOGGER.info(u.getName()+“登录状态”);
return true;
}else{
LOGGER.warn(“请先登录,不要搞事情”);
return false;
}
}
}
拦截器执行顺序的问题
如果有n个拦截器,并且都能拦截到某个URI的时候,执行顺序问题,
在springmvc中当中拦截器定义的先后顺序有关系,配置在前面的优先执行,按照顺序来
例如:有三个拦截器 i1.i2.i3
前置处理顺序:i1,i2,i3
后置处理顺序:i3,i2,i1 拦截器与过滤器的比较
mvc:interceptor <mvc:mapping path="/user/*/"/>
<mvc:exclude-mapping path="/user/login" />
/mvc:interceptor
相似:都有优先处理请求处理的权利,可以决定是否将请求转移到实际处理的控制器处,都可以对请求或者会话当中的数据
进行加工
不同:
拦截器可以做前置处理,也可以做后置处理,还可以完成后处理,控制更加细一些,过滤器只负责前面的过滤的行为而
已
过滤器优先执行
过滤器是servlet规范里面的组件
拦截器都是框架自己额外添加的组件