springMvC的学习

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” %>

Title

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规范里面的组件
    拦截器都是框架自己额外添加的组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值