SpringMVC开发手册
title: SpringMvc -- 开发手册
date: 2018-11-15 22:14:22
tags: SpringMvc
categories: SpringMvc #分类名
type: "SpringMvc"
本片博客记录SpringMvc带给了我们什么?,图解运行流程,以及开发中,常用的注解
SpringMvc基于servlet设计,用于处理用户的请求,基于方法级别拦截,参数通过入参传递,处理器设计为单例模式,和Spring无缝整合, 分离了 控制器,模型对象,让它们更容易被定制
主要组成部分:
- DispatcherServlet:
前端控制器:所有的请求,都会首先被他拦截到,统一给请求分发处理的Handler
- HandlerMapping
处理器映射器: 识别控制器中的注解,目的是找到具体的和Url对应的处理方法
- HanderAdapter
处理器适配器,实例化控制器Controller,调用具体的方法,处理用户发来的请求
- Controller
控制器, 用来处理用户的请求,返回ModelAndView给前端控制器
- ViewResolver
视图解析器: 解析视图(ModeAndView), 把ModelAndView里面的逻辑视图编程一个正真的View对象,并把Model从ModelAndView中取出来
宏观上看,DispatcherServilet是整个web应用的控制器, 微观上,controller是单个http请求处理的控制器
@RequestMapping()
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
// 映射请求方式(get post put delete)
RequestMethod[] method() default {};
//
String[] params() default {};
// 映射请求参数
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
- 支持标注在类上和方法上
- 最常用标注在方法上,用于映射处理前端发送过来的URL
- 如果我们同时把它俩加载类和方法上, 那么请求路径就是两者的路径使用 / 分隔开
// 映射url 映射方法为POST 指定必须包含username 并且age!=10
@RequestMapping(value = "sayHello", method = RequestMethod.POST, params = {"username", "age!=10"})
public String sayHello() {
System.out.println("来到了sayHello");
return "success";
}
@RequestMapping 路径支持通配符
- ? 一个字符
- *任意字符
- ** 多层路径
/**
* 测试 ant风格的占位符
* @return
*/
@RequestMapping("/textAntPath/*/text")
public String textAntPath() {
System.out.println("v");
return "success";
}
@PathVariable 与 @RequestParam()
- @PathVariable 映射URL绑定的占位符(一般在我们添加在方法上的注解上通过{XXX} 占位 )
- @RequestParam取出来的是请求参数,发出的url格式如下:
/**
* 1. 假如:@RequestParam("password") url中并不存在的话, 报错400
* 1.1, 设置@RequestParam的required=false
* 2. 假如只有第一个:@RequestParam("username")String username,String password ( password同样会被装配进去值)
*
SpringMvc的REST风格
浏览器的form表单,只是支持GET POST请求,而Delete put的方法,是不支持的, 我们使用rest风格的提交表单时, 会被SpringMvc的 HiddenHttpMethodFilter拦截下来,过滤处理成标准的http方法,从而支持了 delete put
修改配置文件 web.xml
<!--配置 HiddenHttpMethodFilter 开启RestFul风格 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
jsp
<br>
<a href="text01/1">测试get请求</a>
<br>
<form action="text02" method="post">
<input type="text" name="id">
<input type="submit" value="点击发送post请求">
</form>
<br>
<form action="text03/8" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="点击发送put请求">
</form>
<br>
<form action="text04/7" method="post">
<%-- 我们需要添加隐藏域, name="_method" 不能不写,Spring会拿到它的信息,从而将post转换成 delete --%>
<input type="hidden" name="_method" value="delete">
<input type="submit" value="点击发送delete请求">
</form>
控制器
@RequestMapping(value="text01/{id}",method = RequestMethod.GET)
public String text01(@PathVariable("id")Integer id){
System.out.println("获取id=="+id+"的信息");
return "success";
}
@RequestMapping(value = "text02",method = RequestMethod.POST)
public String text02(@RequestParam Integer id){
System.out.println("新增id=="+id+"的信息");
return "success";
}
@RequestMapping(value = "text03/{id}",method = RequestMethod.PUT)
public String text03(@PathVariable("id") Integer id){
System.out.println("修改id=="+id+"的信息");
return "success";
}
@RequestMapping(value = "text04/{id}",method = RequestMethod.DELETE)
public String text04(@PathVariable("id") Integer id){
System.out.println("删除id=="+id+"的信息");
return "success";
}
@RequestHeader()
映射请求头的信息到入参位置,不同浏览器的请求头的细节可能是不同的
@RequestMapping("/text")
public void text(@RequestHeader(value="Accept-Langnage") String s1){
//
}
@CookieValue()
很常用,在微服务的安全验证模块,安全中心会给满足条件的用户办法token, 存放到浏览器的cookie里面, 用户再次访问就会携带cookie,我们通过这个注解取出cookie的值,进行安全验证
@RequestMapping("textCookieValue")
public String textCookieValue(@CookieValue("JSESSIONID")String jessionId){
System.out.println("cookieValue=="+jessionId);
return "success";
}
POJO绑定请求参数
很多时候前端提交的表单对应着我们将要持久化对象,那么使用pojo绑定参数无疑是一件超赞的事
springMvc支持 按照请求参数名和pojo属性进行自定匹配,自动为该对象填充属性,支持级联属性
JSP
<form action="textPojo">
用户名: <input type="text" name="username">
密码: <input type="text" name="password">
邮箱: <input type="text" name="email">
<%-- 级联属性 --%>
省: <input type="text" name="adress.province">
市: <input type="text" name="adress.city">
<input type="submit" value="提交">
</form>
pojo
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class Person {
String username;
String password;
String email;
Adress adress;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class Adress {
String province;
String city;
}
控制器
springmvc 会自定为我们的入参绑定上前端表单上的数据
@RequestMapping("textPojo")
public String textPojo(Person person){
System.out.println(person);
return "success";
}
支持Servlet原生API
@RequestMapping("textServletAPi")
public String textServletApi(HttpServletRequest request, HttpServletResponse response) {
return "success";
}
处理模型数据
ModelAndView
/**
* springMvc会把ModelAndView的Model放入request域对象中
* @return
*/
@RequestMapping("textModelAndView")
public ModelAndView textModelAndView(){
String viewName="success";
ModelAndView modelAndView = new ModelAndView();
// 设置视图名
modelAndView.setViewName(viewName);
// 添加模型数据
modelAndView.addObject("日期",new Date());
return modelAndView;
}
Map
说白了,就是方法的入参位置可以添加一个 Map或者Model类型的参数,mvc会把隐藏的模型引用传递给这个入参, 从而是开发者可以通过这个入参访问模型中的所有数据,同是可以添加新数据
@RequestMapping("textMap")
public String textMap(Map<String, Object> map) {
map.put("names", Arrays.asList("zhangsan", "lisi"));
return "success";
}
@SessionAttributes
如果我们希望多个请求之间共享某个模型属性数据,那么我们使用
@SeesionAttribute
,她会把我们存放到作用域中的信息备份到Session中
// 她会把我们存放到 作用域中的数据,备份到Session
@SessionAttributes("user",types = String.class)
public class HelloController {
@RequestMapping("textSessionAttribute")
public String textSeesionAttribute(Map<String,Object> map){
Adress adress = new Adress("山东","XXX");
Person zhangsan = new Person("zhangsan", "234234", "4646@qq.com", adress);
map.put("user",zhangsan); // 放入请求域
return "success";
}
在前几个低版本的SpringMvc中版本中,如果本类标记上了
@SessionAttribute
但是却没有标记@ModelAttribute
的方法,服务器报错500;
@ModelAttribute
这个注解可以帮我解决这样一种情况, 更新操作,很多时候,我们只是针对表中的其中几个字段进行更新, 另外一些字段不需要更新(比如插入时间),那怎么做? 如果自己new对象的话,前端的数据绑定到我们new的对象上,插入时间就会空着,这时已更新,原来的插入时间就会被覆盖,于是我们不new ,通常使用
@ModelAttribute
注解标注方法上,先查询数据库,得到有插入时间字段的对象
控制器(标注在方法上):
// 添加上这个注解的方法,会被SpringMvc拦截, 所有的方法在调用前都会先执行这个方法,把查询出来的信息放到作用域
// 这样SpringMvc把前端传递过来的信息,赋值给 作用域里面user -- 狸猫换太子,
// 用户得到的就是被 狸猫
@ModelAttribute
public void textModelAttribute(
@RequestParam(value = "id",required = false) Integer id,
Map<String,Object> map){
// 判断,如果id不为空, 就表示用户想修改信息
// 于是,我们的任务就是 把查数据库,把用户的信息查出来,通过Map放到作用域里面, 谁用,谁取
if(null!=id){
//模拟查库
System.out.println("查询数据库,获取user信息");
Person person = new Person("1", "lisi", "999", "8989@qq.com", new Adress("山西", "北京"));
// 注意点: 在ModelAttribute修饰的方法中,放入作用域的 key 为 类名首字母小写
map.put("person",person);
}
}
@RequestMapping("textModelAttribute2")
public String textModelAttribute2(Person person) // 这里的名字也要和作用域里面的名字相同
{
System.out.println("修改=="+person);
return "success";
}
控制器: (标注在参数上)
**
* 1. 这里的名字随便, 但是上面那个方法的的key 尽量就是类名首字母小写
*
* 2. 使用 添加在入参上 @ModelAttribute(value="XXX") , 则名字随便
*
*@ModelAttribute
* @param user
* @return
*/
@RequestMapping("textModelAttribute2")
public String textModelAttribute2(@ModelAttribute(value = "abc")Person user)
{
自定义视图:
第一步: 实现View
接口
public class HelloView implements View {
/**
* 返回内容类型
* @return
*/
@Override
public String getContentType() {
return "text/html";
}
/**
* 渲染视图
* @param map
* @param httpServletRequest
* @param httpServletResponse
* @throws Exception
*/
@Override
public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
httpServletResponse.getWriter().print("helloViewTime"+new Date());
}
}
第二步: 配置视图解析器
<!-- 配置视图解析器 BeanNameViewResolver 解析器: 使用视图的名字解析视图 (所以我们需要把我们的视图添加进IOC)-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<!-- 到现在为止,我们就有了两个视图解析器,需要指定优先顺序-->
<!-- 常用的放在后边,我们的放前边 order越小,优先级越高-->
<property name="order" value="200"></property>
</bean>
测试
@RequestMapping("textView")
public String textView(){
System.out.println("textView");
// 自定义的视图类名小写
return "helloView";
}
重定向
控制器返回的字符串被当作逻辑视图名称处理
如果返回的字符串中带有forward:
或者redirect:
会被SpringMvc当作指示符特殊处理,后面的字符串当作url路径
@RequestMapping("textRedirect")
public String textRedirect(){
System.out.println("测试重定向!!!");
return "redirect:/index.jsp";
}
数据校验:
当我们添加<mvc:annotation-driven/>
配置,SpringMvc会自动为我们做如下处理
- RequestMappingHandlerMapping
- RequestMappingHanderAdapter
- ExceptionHandlerExceptionResolver 这三个bean
- 支持使用ConversionService对表单参数进行类型转换
- 支持使用@NumberFormatannptation @DateTimeFormat 注解完成数据类型格式化
- 支持使用@Valid 注解对JavaBean 实例惊醒jsr303 验证
- 支持使用@RequestBody和@ResponseBady // 处理ajax
常使用如下连个注解对bean进行校验
@DateTimeFormat(pattern="yyyy-MM-dd")
Date birth;
@NumberFormat(pattern = "#,###,###.#") // #表示数数字
Float salary;
返回Json
@ResponseBody
拦截器
- 实现自己的拦截器实现
HandlerInterceptor接口
重写他的三个方法
preHandle()
作用: 对用户请求request进行处理
调用时机: 在处理器处理请求之前被调用
返回:
true: 如果还需要调用其他拦截器或者是业务处理器
f 何组件处理请求
postHandle()
作用: 对用户请求request进行处理
调用时机: 业务处理器处理完请求之后,DispatcherServlet向客户端相应之前
aferCompletion()
作用: 进行资源清理工作
调用时机: 在DispatcherServlet向客户端响应数据之后调用
配置文件:
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="com.changwu.interceptor.FirstInterceptor"/>
</mvc:interceptors>
- 配置拦截指定请求路径的拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="com.changwu.interceptor.FirstInterceptor"/>
// 配置 专门针对某个求情的拦截器
<mvc:interceptor>
<mvc:mapping path="/textView"/>
<bean class="com.changwu.interceptor.SecondInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
- 多个拦截器的执行顺序
- 第一个拦截器的
firstInterceptor
返回flase,其他拦截器不执行,目标方法不执行 - 第一个拦截器的
firstInterceptor
返回true,第二个拦截器的firstInterceptor
返回false,目标方法不执行,但是第一个拦截器的afterCompletion
方法会执行,回收资源
异常处理--ExceptionHandlerExceptionResolver
SpringMvc 使用HandlerExceptionResolver处理异常
ExceptionHandlerExceptionResolver
主要处理Handler中使用 @ExceptionHandler注解定义的方法
1. 控制器: 出现异常
@RequestMapping("textExceptionHandlerExceptionResolver")
public String textExceptionHandlerExceptionResolver(@RequestParam("i")int i){
System.out.println("result=="+10/i);
return "success";
}
2. 标注有@ExceptionHandler注解的方法 会处理异常
/**
* 捕获数学异常
* 把异常带到页面"ModelAndView
*/
@ExceptionHandler(value=ArithmeticException.class)
public ModelAndView handleArithmeticException(Exception e){
// 通过ModelAndView 把错误信息带到页面
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("errorMsg",e);
System.out.println("异常信息:"+e);
return modelAndView;
}
@ExceptionHandler定义的方法优先级问题,例如发生的是 空指针异常,但是声明异常是 运行时异常和异常, 这时就会报 离空指针异常比较近的 运行时异常
1. 假如出现了数学异常, 它会优先使用下面的第一个异常
@RequestMapping("textExceptionHandlerExceptionResolver")
public String textExceptionHandlerExceptionResolver(@RequestParam("i")int i){
System.out.println("result=="+10/i);
return "success";
}
/**
* 捕获数学异常
* 把异常带到页面"ModelAndView
*
*/
@ExceptionHandler(value=ArithmeticException.class)
public ModelAndView handleArithmeticException(Exception e){
// 通过ModelAndView 把错误信息带到页面
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("errorMsg",e);
System.out.println("异常信息:"+e);
return modelAndView;
}
@ExceptionHandler(value=RuntimeException.class)
public ModelAndView handleRuntimeException(Exception e){
// 通过ModelAndView 把错误信息带到页面
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("errorMsg",e);
System.out.println("{异常信息}:"+e);
return modelAndView;
}
ExceptionHandlerExceptionResolver 内部找不到@ExceptionHandler 注解的话,就会找 @ControllerAdvice 中的 @ExceptionHandler注解方法
/**
* @Author: Changwu
* @Date: 2019/4/14 19:04
*/
@ControllerAdvice
public class HandException {
@ExceptionHandler(value=ArithmeticException.class)
public ModelAndView handleArithmeticException(Exception e){
// 通过ModelAndView 把错误信息带到页面
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("errorMsg",e);
System.out.println("异常信息:"+e);
return modelAndView;
}
}
异常处理-- ResponseStatusExceptionResolver
通过
@ResponseStatus(value="异常信息",code="错误状态码")
注解,定制返回给前端的异常信息以及状态码
异常处理 -- SimpleMappingExceptionResolver
xml文件中进行配置, 指定出现什么异常,跳往哪个页面
<!-- 配置SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- 统一匹配的异常的全类名 跳往的异常页面 -->
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
- 异常信息会自动存储在 作用域 通过
${requestScope.exception}
可以取出来
SpringMVC开发手册的更多相关文章
- Net力软快速信息化系统开发框架 + 开发手册+数据库说明
源码目录结构说明LeaRun.Cache –缓存层LeaRun.Resource –本地语言LeaRun.Utilities –公共类库LeaRun.DataAccess –数据库访问核心组件LeaR ...
- 在线教学、视频会议 Webus Fox(2) 服务端开发手册
上次在<在线教学.视频会议软件 Webus Fox(1)文本.语音.视频聊天及电子白板基本用法>里介绍了软件的基本用法.本文主要介绍服务器端如何配置.开发. 1. 配置 1.1 IIS配置 ...
- 在线教学、视频会议 Webus Fox(3) 客户端开发手册
本文主要介绍webus fox 客户端的配置及接口说明. 1. 文件列表和配置 1.1 文件列表 1.2 common.xml 配置 根据服务器端的部署, 替换[ServerUrl] , [RtmpP ...
- Navi.Soft30.开放平台.聚合.开发手册
1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...
- Navi.Soft30.开放平台.腾讯.开发手册
1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...
- Navi.Soft30.开放平台.百度.开发手册
1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...
- Navi.Soft30.框架.WinForm.开发手册
阅读导航 Navi.Soft30.Core类库.开发手册 http://www.cnblogs.com/xiyang1011/p/5709489.html Navi.Soft30.框架.WinForm ...
- Discuz!开发手册
如何使用Discuz开发手册? 1.首先建议你了解Discuz目录结构-全局篇 通过对目录结构的了解,会在以后的创作道路上提供坚实的基础! 2.你还需要了解Discuz! X3.1数据字典 3.创建自 ...
- dzzoffice教程、文档、开发手册等内容地址
dzzoffice教程.文档.开发手册等内容全部都存放在DzzOffice开发者社区的文集中.搜索引擎收录不到DzzOffice中的应用内容,这里将文集地址提供在这里. 地址:http://dev.d ...
随机推荐
- Bean的构造器注入和setter注入
链接:https://pan.baidu.com/s/1vixLrr8harzZMwLsIB1Mwg 提取码:ou1n 首先要明白,为什么要注入? IOC容器会在初始化时,创建好所有的bean对象的实 ...
- Shell的常用十八条命令
Shell的18条常用命令整理 1. ls: 类似于dos下的dir命令 ls最常用的参数有三个: -a -l -F. ls –a Linux上的文件以.开头的文件被系统视为隐藏文件,仅用ls命令是看 ...
- spring data jpa Specification 复杂查询+分页查询
当Repository接口继承了JpaSpecificationExecutor后,我们就可以使用如下接口进行分页查询: /** * Returns a {@link Page} of entitie ...
- flask之上下文管理
简单来说,falsk上下文管理可以分为三个阶段: 1.请求进来时,将请求鞋底的相关数据放入上下文管理中进行管理 2.在视图函数中,要去上下文管理中取值 3.请求响应之后,要将上下文管理中的数据清除 详 ...
- git合并丢失代码问题分析与解决(错误操作导致)
问题描述 我们在主干dev和branch1分支上进行并行开发.当要把branch1功能的代码合并到dev上时,发现dev上开发的部分功能代码找不到了. 那么,是在branch1上,作了删除提交导致的吗 ...
- 编程的智慧(王垠)(http://www.cocoachina.com/programmer/20151125/14410.html)
编程是一件创造性的工作,是一门艺术.精通任何一门艺术,都需要很多的练习和领悟,所以这里提出的“智慧”,并不是号称三天瘦二十斤的减肥药,它并不能代替你自己的勤奋.然而我希望它能给迷惑中的人们指出一些正确 ...
- mysql常见函数及其用例
函数调用:select 函数名(实参列表) [from 表]; 函数分类: 1.单行函数 如 concat.length.ifnull等. 2.分组函数 功能:做统计使用,又称为统计函数.聚合函数.组 ...
- linux 防止误操作 mysql 数据库技巧
mysql 帮助说明 1[oldboy_c64 ~]# mysql --help|grep dummy 2 -U, --i-am-a-dummy Synonym for option --safe-u ...
- linux 更改 mysql 管理员口令
#更改口令前,确保 mysql 服务已经正常启动 mysqladmin –u root passwd 新口令 #登陆 mysql ./mysql –u root –p Enter password:新 ...
- mailstats - 显示邮件状态信息
总览 mailstats [-o] [-C cffile] [-f stfile] 描述 mailstats工具显示当前的邮件状态信息. 首先,先显示统计启动时所记录的时间,当然是以ctime(3)所 ...