SpringMVC入门学习三
今天是Springmvc学习的第三天,今天我将主要介绍一下:
- 常用注解的使用
- 关于非post、get请求的处理
- 文件上传与下载
- 拦截器

常用注解的使用
老大在此
@Controller
@Controller放在类的上面,用于将一个类标记为Controller,处理DispatcherServlet分发的请求,当然真正处理请求的还是使用@RequestMapping注解的方法。
处理request URI的注解
@RequestMapping
@RequestMapping是一个用来处理请求地址映射的注解,可用于类上面【代表模块】和方法上面【代表业务】
里面参数属性
,其中所有的参数都可以传入数组
的形式:
value:代表请求的地址如"/login",可以写多个【使用数组】,只写它时,可以省略不写
name:value的别名,作用是一样的。
method:请求的method类型,里面要传入
RequestMethod
类型的数据,如GET,POST,PUT等等,可以指令多个(使用数组传递即可)
它的衍生品:- @GetMapping:专门处理get请求
- @PostMapping:专门处理Post请求
params:设置需要的参数,如果没有,请求就过不去,还可以设置参数是否等于或则不等于
// 当穿过来的参数data不为not才进行响应
@RequestMapping(value = "/test1",params = "data!=not")
// 当穿过来的参数data为hava才进行响应
@RequestMapping(value = "/test1",params = "data=have")
ps:中间注意
别打空格
headers
指定request中必须包含某些指定的header值,该方法才会处理请求。@RequestMapping(value="/hello",headers="Referer=https://baidu.com")
consumes 消费者,指令请求提交内容的类型(Content-Type),例如可以限令必须为application/json;charset=UTF-8,指令多个使用数组形式
produces 生产者,指令放回的内容的类型,但是必须是请求头所包含的类型
@PathVariable
这个是restful风格的请求方式,用于将URL中的模板变量映射到方法的参数上面,这个在我的上一篇博客有所介绍。
共享数据
@ModelAttribute
@ModelAttribute注解可以被应用在方法参数上面和方法声明上面。其中被@ModelAttribute注解的方法会优先于controller方法(被@RequestMapping注解)之前执行,因为模型对象优先于controller方法创建。
简单的来说,@ModelAttribute有两个作用,将数据保存在model上面
【标注在方法上面】,将数据从model取出来
【标注在参数里面】
将数据保存在model上面
使用@ModelAttribute注解无返回值方法
@ModelAttribute
public void model1(Model model){
model.addAttribute("modle1","你好呀");
} @RequestMapping("/modleC")
public String modleC(){
return "test";
}
其实这个就相当于
@RequestMapping("/modleC")
public String modleC(Model model){
model.addAttribute("modle1","你好呀");
return "test";
}
注解有返回值的方法
/**
* 注解有返回值的
* 在这种情况下,放回值对象会默认的放在隐藏的Model中。
* 其key为放回值 **类型** 首字母小写,当然也可以在@ModelAttribute
* 加上value或则name的属性来指令key
* @return
*/
@ModelAttribute
public String modeler02(){
String Hello = "你好呀";
return Hello;
//在这里面key为string
}
与@RequestParam结合使用
@RequestParam的具体用法将在下面介绍加入此时我们发送了一个这样的请求:
/test/name=googboy
// 取出get请求的参数name,将其存入modle中
@ModelAttribute("name")
public String modeler02(@RequestParam()String name){
return name;
} @RequestMapping("/test")
public String test(){
return "test";
}
将数据从model取出来
假如此时有了一个model,key为name,value为Tom
数据,那么我们可以通过@ModelAttribute将数据取出来。
@RequestMapping("/test")
public String test(@ModelAttribute("name")String name){
// 输出是 名字是Tom
System.out.println("名字是"+name);
return "test";
}
保存数据
@SessionAttributes
假如希望在多个请求之间共用数据,则可以在控制器类上面标注一个@SessionAttributes,其中value指令是model中的哪一个存入session,type为数据类型,两者都可以放数组类型的数据。

取出数据
@SessionAttribute
@SessionAttribute的作用很简单,就是获得session的值
假如此时有一个session key为name,value为Tom
,获得session
@RequestMapping("/test2")
public String test2(@SessionAttribute("name") String name){
System.out.println("session结果是"+name);
return "test";
}
假如此时不存在就会报错,这是可以使用required来确定是否必须
@RequestMapping("/test2")
//非必须,同时value/name必须加上
public String test2(@SessionAttribute(value = "name",required = false) String name){
System.out.println("session结果是"+name);
return "test";
}
对于取出参数的处理
@RequestParam
@RequestParam主要是用于在Springmvc后台控制层获得参数,类似request.getParameter("name")
它有下列参数
value:value表示要取出的参数,当只有value这个参数时,可以省略不写。
name:value的别名,作用和value一样。
required:默认值是true,当传入的参数值不存在时,程序就会报错,这时候就可以将required设置为false。
defaultValue:当设置defaultValue时,会自动的将required设置为false,如果此时请求参数不存在,就会默认的将参数设置为defaultValue。当然,如果参数存在,defaultValue也就是不会发挥作用了。
举个栗子:
@RequestMapping("/test3")
public String test3(@RequestParam(value = "name",defaultValue = "TomCat") String name){
// 请求网址是: /test3
// 输出是 名字是TomCat
System.out.println("名字是"+name);
return "test";
}
@RequestBody
这时候大家可能会问,既然有@RequestParam来处理方式了,为什么我们还要使用@RequestBody来获取参数呢?
这个主要主要是因为他们处理数据的类型Content-Type
不一样
@RequestParam:处理application/x-www-form-urlencoded编码的内容,提交方式为Get,Post。
@RequestBody:通常是来处理非
application/x-www-form-urlencoded编码格式
的内容的数据,比如说application/json
和application/xml
。
既然是处理json数据,那么就需要使用json的jar包。
<!--====>jackson包导入start-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.7</version>
</dependency>
<!--====>jackson包导入end-->
当发了一个如下所示的json请求时
$(document).ready(function () {
$("button").click(function () {
$.ajax({
url: "/test4",
type:"post",
data:JSON.stringify({
"name":"TODO"
}),
dataType:"json",
contentType:"application/json; charset=utf-8",
success:function (data) {
console.log(data)
}
});
});
});
controller代码,在参数里面加上@RequestBody:
@RequestMapping("/test4")
public String test4(@RequestBody String name){
// 名字是{"name":"TOFO"}
System.out.println("名字是"+name);
return "test";
}
对于返回数据的处理
@ResposeBody
返回json数据
在大多数的情况下,我们不一定是想返回一个视图,只想返回一个json数据或者说xml数据,那么这时候我们就要使用@RequestBody了。@ResponseBody注解被应用于方法上,标志着响应会写到响应体里面去,而不是放到视图Model里面去。
那么就可以这样使用:
@RequestMapping(value = "/test4")
@ResponseBody
public User test4(@RequestBody String name){
// 名字是{"name":"TOFO"}
System.out.println("名字是"+name);
User u = new User();
u.setName("小明");
u.setAge("17");
return u;
}
返回xml数据
要导入额外的jacksonxml jar包
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.7</version>
</dependency>
// 由于要返回xml格式的数据,所以需要设置produces为application/xml
// 使用MediaType里面的静态常量,可以防止写错
@ResponseBody
@RequestMapping(value = "/test5",produces = org.springframework.http.MediaType.APPLICATION_XML_VALUE)
public User test5(){
User u = new User();
u.setName("小红");
u.setAge("18");
return u;
}
SpringMVC关于非post、get请求的处理
在HTML5的规范中,表单元素唯二允许的HTTP的方法是GET和POST,但是如果我们想使用PUT或则DELET方法,那怎么办呢?
- 在浏览器中装作自己是post或则get请求,实际上是PUT请求
<!-- 装成自己是post请求 -->
<form action="/put" method="post">
<!-- 实际上想发送的PUT请求 -->
<input type="hidden" name="_method" value="PUT">
姓名 <input name="name" type="text">
<input type="submit" value="提交">
</form>
- 在web.xml文件中,从
_method
找到真正的http请求
加入
<filter>
<!-- 原理就是从_method找到真正想要http请求,然后分发给controller
所以这个必须写在DispatcherServlet的前面
-->
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
<!--注册一个前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--上下文配置的位置的制定-->
<param-name>contextConfigLocation</param-name>
<!--此时是在类路径下面去寻找-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<!--servlet的映射配置-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--这里统一写/-->
<url-pattern>/</url-pattern>
</servlet-mapping>
文件上传与下载
文件上传
文件上传同时也是使用form表单进行提交,一般我们的表单的提交是文本型的数据,实际上就是进行字符串的拼接。那么文件便不是这样的进行处理,这时候我们就要使用到multipart表单了。
首先我们的配置一个MultipartResolver来告诉DispatchServlet如何来处理multipart请求。
在Servlet3.0中,Spring会默认注册一个StandardServletMultipartResolver,我们只需要在web.xml启用<multipart-config>
就行。
<multipart-config>
<location>/tmp</location>
</multipart-config>
属性 | 作用 |
---|---|
location | 上传文件所存放的临时目录。必须指定 |
max-file-size | 文件的最大大小,单位为字节。默认没有限制 |
max-request-size | 请求的最大大小,单位为字节。默认没有限制 |
file-size-threshold | 文件大小阈值,当大于这个阈值时将写入到磁盘,否则在内存中。默认值为0 |
前端代码
<form action="/upload" method="post" enctype="multipart/form-data">
文件 <input type="file" name="file"/>
<input type="submit" value="提交">
</form>
控制文件上传的代码
@RequestMapping("/upload")
public String upload(@RequestParam("file")MultipartFile file, HttpServletRequest request) {
// 假如没有文件
if (!file.isEmpty()) {
// 获得文件原始名字
String fileName = file.getOriginalFilename();
// 获得文件的后缀名
String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
// 取新的名字 UUID可以保证产生的名字不一样,产生全球唯一的ID
String newName = UUID.randomUUID() + fileSuffix;
// 获取文件存储目录地址
String filePath = request.getSession().getServletContext().getRealPath("/upload");
File fileForPath = new File(filePath);
// 如果文件不存在
if (!fileForPath.exists()) {
// 新建文件
fileForPath.mkdir();
}
File targetFile = new File(filePath, newName);
try {
// 将文件写入
file.transferTo(targetFile);
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("文件不存在");
}
return "test";
}
文件下载
@RequestMapping("down")
public String down(HttpServletResponse response,HttpServletRequest request){
// 假如我的文件在/home/xiaohiu/images/鬼刀.jpg
String fileName= "鬼刀.jpg";
String parentPath = "/home/xiaohiu/images";
// 这时候path.toString就是/home/xiaohiu/images/鬼刀.jpg了
Path path = Paths.get(parentPath,fileName);
// 假如文件存在
if (Files.exists(path)){
// 取出后缀名 jpg
String fileSuffix = fileName.substring(fileName.lastIndexOf(".")+1);
// 设置ContentType,只有设置它,才会去下载
response.setContentType("application/"+fileSuffix);
try {
// 添加头信息 同时对文件名重新编码防止中文名乱码
response.addHeader("Content-Disposition","attachment;filename="+new String(fileName.getBytes("utf-8"),"ISO8859-1"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
// 使用输出流写出去
Files.copy(path,response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}else {
System.out.println("文件不存在");
}
return "test";
}
SpringMVC拦截器
拦截器实在我们请求之前做检查,同时有权决定我们接下来是否继续,同时也可以对我们的请求进行加工处理,可以设置多个拦截器。
看到这里,是不是想到了我在前面介绍的AOP
,其实我们可以理解为Spring拦截器是
SpringMVC对AOP的一种实现方式。AOP是通过配置<aop:config>
进行配置,而拦截器是通过<mvc:interceptors>
进行配置。
那么我们怎么实现呢?
实现HandlerInterceptorAdapter接口
在SpringMVC中,为实现拦截器功能,有两种方式,一个是实现
HandlerInterceptor
接口,第二个是实现WebRequestInterceptor
接口,这里我们选择使用HandlerInterceptor。在HandlerInterceptor接口中,定义了三个方法
preHandle():请求之前调用,返回
true
或则false
,返回true,接下来的postHandle和afterCompletion才会起作用。postHandle():在请求之后调用,也就是controller方法执行完后再调用,但是却是在DispatcherServlet进行
视图返回渲染之前
被调用。也就是说,这个可以对modle进行操作。afterCompletion():在DispatcherServlet进行完试图渲染之后才执行。
public class TestInterceptor implements HandlerInterceptor { @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("请求前进行拦截"); // 返回true才会查找下一个拦截器,如果没有下一个拦截器,则返回controller
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("视图渲染前进行拦截");
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("视图渲染后进行拦截");
}
}
拦截器的配置
在springmvc的xml配置文件中
<!--配置拦截器-->
<mvc:interceptors>
<!--配置一个拦截器
可以配置多个,那么拦截顺序则是从上到下
-->
<mvc:interceptor>
<!--拦截的URI
/* 代表拦截这一层的任意字符
/** 代表拦截任意层次的任意字符
-->
<mvc:mapping path="/*"/>
<!--不进行拦截的uri-->
<mvc:exclude-mapping path="/get"/>
<bean class="cc.weno.interceptor.TestInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
这时候就可以进行拦截了。
拦截器顺序的问题
拦截器顺序是根据配置的顺序来决定的,但是pre、post、after却有些区别,这张图就可以表示了。
好了,今天的Springmvc就到了这里了。
君子不行陌路,管它咫尺还是天涯
SpringMVC入门学习三的更多相关文章
- SpringMVC入门学习(二)
SpringMVC入门学习(二) ssm框架 springMVC 在上一篇博客中,我简单介绍了一下SpringMVC的环境配置,和简单的使用,今天我们将进一步的学习下Springmvc的操作. mo ...
- SpringMVC入门学习(一)
SpringMVC入门学习(一) ssm框架 spring SpringMVC是一个Java WEB框架,现在我们知道Spring了,那么,何为MVC呢? MVC是一种设计模式,其分为3个方面 mo ...
- SCARA——OpenGL入门学习三
OpenGL入门学习[三] 在第二课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处.例如:点太小,难以看清楚:直线也太细,不舒服:或者想画虚线,但不知道方法只能用 ...
- Egg入门学习(三)---理解中间件作用
Egg是基于koa的,因此Egg的中间件和Koa的中间件是类似的.都是基于洋葱圈模型的. 在Egg中,比如我想禁用某些IP地址来访问我们的网页的时候,在egg.js中我们可以使用中间件来实现这个功能, ...
- SpringMVC入门学习案例笔记
一.数据库环境用mysql,数据库建表语句如下: /* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ************* ...
- SpringMVC基础学习(三)—参数绑定
一.基本数据类型的绑定 页面 <form action="${pageContext.request.contextPath}/test.do" method="p ...
- MongoDB入门学习(三):MongoDB的增删查改
对于我们这样的菜鸟来说,最重要的不是数据库的管理,也不是数据库的性能,更不是数据库的扩展,而是怎么用好这款数据库,也就是一个数据库提供的最核心的功能,增删查改. 由于M ...
- springMVC入门(三)------springMVC的处理器映射器和处理器适配器配置
简介 springMVC的处理器映射器和处理器适配器存在多种配置,因此在此专门做一个总结 常见处理器映射器.适配器的配置 springmvc多个映射器多个处理器可以并存 所有的映射器都实现了Handl ...
- Springmvc入门基础(三) ---与mybatis框架整合
1.创建数据库springmvc及表items,且插入一些数据 DROP TABLE IF EXISTS `items`; CREATE TABLE `items` ( `id` int(11) NO ...
随机推荐
- html table 保存到excel中
引用:HTML中的table导出为Excel文件 <!DOCTYPE html> <html lang="en"> <head> <met ...
- servlet从mysql中取数据时出现的汉字编码问题
取出的汉字都是问号 之后根据网友提示在输出之前对response进行编码设置 正常显示
- spring InitializingBean和DisposableBean init-method 和destroy-method @PostConstruct @PreDestroy
对于初始化函数: @PostConstruct 注解的方法 InitializingBean接口定义的回调afterPropertiesSet() Bean配置中自定义的初始化函数 对于析构则与上相同 ...
- recyclerview刷新
https://blog.csdn.net/leejizhou/article/details/51179233 RecyclerView之更新UI数据的高级用法 https://www.cnblog ...
- Python TypeError: 'module' object is not callable 原因分析
今天尝试使用pprint进行输出,语句为 >>>import pprint >>>pprint(people) 结果报错,TypeError: 'module' o ...
- 2019/3/2周末 java集合学习(一)
Java集合学习(一) ArraysList ArraysList集合就像C++中的vector容器,它可以不考虑其容器的长度,就像一个大染缸一 样,无穷无尽的丢进去也没问题.Java的数据结构和C有 ...
- Scala中的Implicit详解
Scala中的implicit关键字对于我们初学者像是一个谜一样的存在,一边惊讶于代码的简洁, 一边像在迷宫里打转一样地去找隐式的代码,因此我们团队结合目前的开发工作,将implicit作为一个专题进 ...
- [转载]你所不了解的DevOps
DevOps开发运维训练营 一旦建立了创新的文化,即使那些并非科学家或者工程师的人——诗人.演员.记者——也能以团体的形式,接受科学文化的意义.他们信奉创新文化的概念.他们以促进这种文化的方式投票.他 ...
- 配置IDM不限速下载百度云的大文件
IDM介绍Internet Download Manager(简称IDM)是一个用于Windows系统的下载管理器,它是共享软件,免费试用期为30天,但是每月均有一段时间优惠. IDM可以让用户自动下 ...
- Docker学习笔记-Redis 安装
拉取官方的镜像 docker pull redis:3.2 查看 docker images redis 运行容器 docker run -p 6379:6379 -v $PWD/data:/data ...