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>
  • 多个拦截器的执行顺序
  1. 第一个拦截器的firstInterceptor返回flase,其他拦截器不执行,目标方法不执行
  2. 第一个拦截器的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开发手册的更多相关文章

  1. Net力软快速信息化系统开发框架 + 开发手册+数据库说明

    源码目录结构说明LeaRun.Cache –缓存层LeaRun.Resource –本地语言LeaRun.Utilities –公共类库LeaRun.DataAccess –数据库访问核心组件LeaR ...

  2. 在线教学、视频会议 Webus Fox(2) 服务端开发手册

    上次在<在线教学.视频会议软件 Webus Fox(1)文本.语音.视频聊天及电子白板基本用法>里介绍了软件的基本用法.本文主要介绍服务器端如何配置.开发. 1. 配置 1.1 IIS配置 ...

  3. 在线教学、视频会议 Webus Fox(3) 客户端开发手册

    本文主要介绍webus fox 客户端的配置及接口说明. 1. 文件列表和配置 1.1 文件列表 1.2 common.xml 配置 根据服务器端的部署, 替换[ServerUrl] , [RtmpP ...

  4. Navi.Soft30.开放平台.聚合.开发手册

    1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...

  5. Navi.Soft30.开放平台.腾讯.开发手册

    1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...

  6. Navi.Soft30.开放平台.百度.开发手册

    1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...

  7. Navi.Soft30.框架.WinForm.开发手册

    阅读导航 Navi.Soft30.Core类库.开发手册 http://www.cnblogs.com/xiyang1011/p/5709489.html Navi.Soft30.框架.WinForm ...

  8. Discuz!开发手册

    如何使用Discuz开发手册? 1.首先建议你了解Discuz目录结构-全局篇 通过对目录结构的了解,会在以后的创作道路上提供坚实的基础! 2.你还需要了解Discuz! X3.1数据字典 3.创建自 ...

  9. dzzoffice教程、文档、开发手册等内容地址

    dzzoffice教程.文档.开发手册等内容全部都存放在DzzOffice开发者社区的文集中.搜索引擎收录不到DzzOffice中的应用内容,这里将文集地址提供在这里. 地址:http://dev.d ...

随机推荐

  1. OSPF与ACL 综合应用

    1.企业内网运行OSPF路由协议,区域规划如图所示:2.财务和研发所在的区域不受其他区域链路不稳定性影响:3.R1.R2.R3只允许被IT登录管理:4.YF和CW之间不能互通,但都可以与IT互通:5. ...

  2. JetBrains视图

    三种视图模式:

  3. 洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)

    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1311990 原题地址:洛谷P1155 双栈排序 ...

  4. 小白学Python(19): Pyinstaller 生成 exe 文件

    python 默认并不包含 PyInstaller 模块,因此需要自行安装 PyInstaller 模块. 安装 PyInstaller 模块与安装其他 Python 模块一样,使用 pip 命令安装 ...

  5. 小白如何入门 Python 爬虫?

    本文针对初学者,我会用最简单的案例告诉你如何入门python爬虫! 想要入门Python 爬虫首先需要解决四个问题 熟悉python编程 了解HTML 了解网络爬虫的基本原理 学习使用python爬虫 ...

  6. 数学: HDU1005 Number Sequence

    Number Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. POJ 3259 Wormholes SPFA算法题解

    版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/,未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...

  8. 坐标轴刻度取值算法-基于魔数数组-源于echarts的y轴刻度计算需求

    本文链接:https://blog.csdn.net/qq_26909801/article/details/96966372数值型坐标轴刻度计算算法前言算法描述上代码代码运行效果结语前言因实习的公司 ...

  9. java体系中OOP,OOD,OOA分别代表什么含义,以及OA,CRM,ERP

    OOP:Object Oriented Programming 面向对象程序设计. OOD:Object Oriented Design 面向对象设计. OOA:Object Oriented Ana ...

  10. ukhj

    SQL解析顺序: 七种Join图: