spring mvc: 基础用法,比如controller,参数校验,异常处理,返回状态码,返回数据格式,
请求参数格式:
@RequestParam, @RequestBody, @PathVaribale
URI = Universal Resource Identifier 统一资源标志符
URL = Universal Resource Locator 统一资源定位符
URN = Universal Resource Name 统一资源名称
1.@Controller
标记在类上,使用它标记的类就是一个SpringMVC Controller对象,分发处理器会扫描使用该注解的类的方法,检测该方法是否使用了@RequestMapping注解。
@Controller只是定义了一个控制器,使用@RequestMapping注解的方法才是真正处理请求的处理器。
2.URI模板(@PathVariable)
URI模板就是在URI中给定一个变量,然后在映射的时候动态的给变量赋值
http://localhost/{variable1}
这个模板中包含一个变量variable1
在SpringMVC中,我们可以使用@PathVariable来标记一个Controller的处理方法参数,表示该参数的值将使用URI模板中对应的变量的值来赋值
@Controller
@RequestMapping ( “/test/{variable1}” )public class MyController {
@RequestMapping ( “/showView/{variable2}” )
public ModelAndView showView( @PathVariable String variable1, @PathVariable ( “variable2” ) int variable2) {}
@PathVariable(“variable2”)表明对应的是URI模板中的{variable2},没()则是跟参数名相同的变量
3.@RequestParam绑定HttpServletRequest请求参数到控制器方法参数
@RequestMapping ( “requestParam” )
public String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( “age” ) int age) {
return “requestParam” ;
}
/requestParam.do?name=hello&age=1
利用@RequestParam从HttpServletRequest中绑定了参数name到控制器方法参数name,绑定了参数age到控制器方法参数age。跟@PathVariable一样,指明。还有个required属性,表明该属性是否必要存在
4.使用 @CookieValue 绑定 cookie 的值到 Controller 方法参数
5.使用 @RequestHeader 注解绑定 HttpServletRequest 头信息到Controller 方法参数
大小写不敏感
6.@RequestMapping的属性
6.1params属性
@RequestMapping (value= “testParams” , params={ “param1=value1” , “param2” , “!param3” })
在上面的代码中我们用@RequestMapping 的params 属性指定了三个参数,这些参数都是针对请求参数而言的,它们分别表示参数param1 的值必须等于value1 ,参数param2 必须存在,值无所谓,参数param3 必须不存在,只有当请求/testParams.do 并且满足指定的三个参数条件的时候才能访问到该方法。所以当请求/testParams.do?param1=value1¶m2=value2 的时候能够正确访问到该testParams 方法
6.2 method
method 属性主要是用于限制能够访问的方法类型的。
6.3 Headers
使用headers属性可以通过请求头信息来缩小@RequestMapping的映射范围
@RequestMapping (value= “testHeaders” , headers={ “host=localhost” , “Accept” })
headers 属性的用法和功能与params 属性相似。在上面的代码中当请求/testHeaders.do 的时候只有当请求头包含Accept 信息,且请求的host 为localhost 的时候才能正确的访问到testHeaders 方法。
7.用@RequestMapping标记的处理器方法支持的方法参数和返回类型
7.1支持的方法类型
(1)HttpServlet对象 HttpServletRequest,HttpServletResponse,HttpSession
这些参数Spring 在调用处理器方法的时候会自动给它们赋值,所以当在处理器方法中需要使用到这些对象的时候,可以直接在方法上给定一个方法参数的申明,然后在方法体里面直接用就可以了但是有一点需要注意的是在使用HttpSession 对象的时候,如果此时HttpSession 对象还没有建立起来的话就会有问题。
(2 )Spring 自己的WebRequest 对象。 使用该对象可以访问到存放在HttpServletRequest 和HttpSession中的属性值。
(3 )InputStream 、OutputStream 、Reader 和Writer 。 InputStream 和Reader 是针对HttpServletRequest 而言的,可以从里面取数据;OutputStream 和Writer 是针对HttpServletResponse 而言的,可以往里面写数据。
(4 )使用@PathVariable 、@RequestParam 、@CookieValue 和@RequestHeader 标记的参数。
(5 )使用@ModelAttribute 标记的参数。
(6 )java.util.Map 、Spring 封装的Model 和ModelMap 。 这些都可以用来封装模型数据,用来给视图做展示。
(7 )实体类。 可以用来接收上传的参数。
(8 )Spring 封装的MultipartFile 。 用来接收上传文件的。
(9 )Spring 封装的Errors 和BindingResult 对象。 这两个对象参数必须紧接在需要验证的实体对象参数之后,它里面包含了实体对象的验证结果。
7.2. 支持的返回类型
(1 )一个包含模型和视图的ModelAndView 对象。
(2 )一个模型对象,这主要包括Spring 封装好的Model 和ModelMap ,以及java.util.Map ,当没有视图返回的时候视图名称将由RequestToViewNameTranslator 来决定。
(3 )一个View 对象。这个时候如果在渲染视图的过程中模型的话就可以给处理器方法定义一个模型参数,然后在方法体里面往模型中添加值。
(4 )一个String 字符串。这往往代表的是一个视图名称。这个时候如果需要在渲染视图的过程中需要模型的话就可以给处理器方法一个模型参数,然后在方法体里面往模型中添加值就可以了。
(5 )返回值是void 。这种情况一般是我们直接把返回结果写到HttpServletResponse 中了,如果没有写的话,那么Spring 将会利用RequestToViewNameTranslator 来返回一个对应的视图名称。如果视图中需要模型的话,处理方法与返回字符串的情况相同。
(6 )如果处理器方法被注解@ResponseBody 标记的话,那么处理器方法的任何返回类型都会通过HttpMessageConverters 转换之后写到HttpServletResponse 中,而不会像上面的那些情况一样当做视图或者模型来处理。
(7 )除以上几种情况之外的其他任何返回类型都会被当做模型中的一个属性来处理,而返回的视图还是由RequestToViewNameTranslator 来决定,添加到模型中的属性名称可以在该方法上用@ModelAttribute(“attributeName”) 来定义,否则将使用返回类型的类名称的首字母小写形式来表示。使用@ModelAttribute 标记的方法会在@RequestMapping 标记的方法执行之前执行。
8.@ModelAttribute
@RequestMapping ( “/myTest” )public class MyController {
@ModelAttribute ( “hello” )
public String getModel() {
return “world” ;}
@RequestMapping ( “sayHello” )
public void sayHello( @ModelAttribute ( “hello” ) String hello, Writer writer) throws IOException {
writer.write( "Hello " + hello);}}
在上面代码中,当我们请求/myTest/sayHello.do 的时候,由于MyController 中的方法getModel 使用了注解@ModelAttribute 进行标记,所以在执行请求方法sayHello 之前会先执行getModel 方法,这个时候getModel 方法返回一个字符串world 并把它以属性名hello 保存在模型中,接下来访问请求方法sayHello 的时候,该方法的hello参数使用@ModelAttribute(“hello”) 进行标记,这意味着将从session 或者模型中取属性名称为hello 的属性值赋给hello 参数,所以这里hello 参数将被赋予值world ,所以请求完成后将会在页面上看到Hello world 字符串。
@SessionAttributes 用于标记需要在Session 中使用到的数据,包括从Session 中取数据和存数据。@SessionAttributes 一般是标记在Controller 类上的,可以通过名称、类型或者名称加类型的形式来指定哪些属性是需要存放在session 中的。
POJO:
简单Java对象,指那些没有从任何类继承、也没实现任何接口,更没有被其他框架侵入的java对象
用于数据的临时传递,只能装载数据,有get,set方法,而不具备业务逻辑处理能力
JavaBean:
是一种JAVA语言写成的可重用组件
1.这个类必须有一个公共的无参构造函数
2.这个类的属性通过getter和setter来访问
3.这个类是可序列化的
Spring MVC数据校验:
就是用来验证客户输入的数据是否合法,比如客户登录时,用户名不能为空,或者不能超出指定长度等要求,这就叫做数据校验。
数据校验分为客户端校验和服务端校验
1.引入依赖
Spring-boot-starter-web
(子依赖有 hibernate-validator
Jackson-databind)
2.构建启动类
3.创建需要被校验的实体类
Public class Foo{
@NotBlank
Private String name;
@Min(18)
Private Integer age;
@Email(message=“邮箱格式错误”)
Private String email;}
4.在@Controller中校验数据
@Controller
Public class FooController{
@RequestMapping(“/foo”)
Public String foo(@Validated Foo foo,BindingResult bindingResult){
If(bindingResult.hasErrors()){
for(FieldError fieldError:bindingResult.getFieldError()){}
Return “fail”;
}}
SpringMVC中自带的简单异常处理器
异常处理:系统的dao,service,controller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。
三种处理异常方式:
1.使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver
2.实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
3.使用@ExceptionHandler注解实现异常处理
@Repository生成该类或接口的实现类
3.3 集成异常处理
3.3.1 使用SimpleMappingExceptionResolver实现异常处理
1、在Spring的配置文件applicationContext.xml中增加以下内容:
Xml代码
1.
2.
3.
4.
5.
6.
7.
8.
9. error-business
10. error-parameter
11.
12.
13.
14.
15.
2、启动测试项目,经验证,Dao层、Service层、Controller层抛出的异常(业务异常BusinessException、参数异常ParameterException和其它的异常Exception)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。
3、从上面的集成过程可知,使用SimpleMappingExceptionResolver进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。
3.3.2 实现HandlerExceptionResolver 接口自定义异常处理器
1、增加HandlerExceptionResolver 接口的实现类MyExceptionHandler,代码如下:
Java代码
1.public class MyExceptionHandler implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
2. Exception ex) {
3. Map<String, Object> model = new HashMap<String, Object>();
4. model.put(“ex”, ex);
5. // 根据不同错误转向不同页面
6. if(ex instanceof BusinessException) {
7. return new ModelAndView(“error-business”, model);
8. }else if(ex instanceof ParameterException) {
9. return new ModelAndView(“error-parameter”, model);
10. } else {
11. return new ModelAndView(“error”, model); } } }
、在Spring的配置文件applicationContext.xml中增加以下内容:
1.
3、启动测试项目,经验证,Dao层、Service层、Controller层抛出的异常(业务异常BusinessException、参数异常ParameterException和其它的异常Exception)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。
4、从上面的集成过程可知,使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。
3.3.3 使用@ExceptionHandler注解实现异常处理
1、增加BaseController类,并在类中使用@ExceptionHandler注解声明异常处理,代码如下:
Java代码
1.public class BaseController {
2. /** 基于@ExceptionHandler异常处理 */
3. @ExceptionHandler
4. public String exp(HttpServletRequest request, Exception ex) {
5.
6. request.setAttribute(“ex”, ex);
7.
8. // 根据不同错误转向不同页面
9. if(ex instanceof BusinessException) {
10. return “error-business”;
11. }else if(ex instanceof ParameterException) {
12. return “error-parameter”;
13. } else {
14. return “error”;
15. }
16. }
17.}
2、修改代码,使所有需要异常处理的Controller都继承该类,如下所示,修改后的TestController类继承于BaseController:
Java代码
1.public class TestController extends BaseController
3、启动测试项目,经验证,Dao层、Service层、Controller层抛出的异常(业务异常BusinessException、参数异常ParameterException和其它的异常Exception)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。
4、从上面的集成过程可知,使用@ExceptionHandler注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BaseController即可)、不需要附加Spring配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于BaseController),在异常处理时不能获取除异常以外的数据。
3.4 未捕获异常的处理
对于Unchecked Exception而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进行相应的捕获和处理,则我们可能不得不面对尴尬的404、500……等服务器内部错误提示页面。
我们需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在Web.xml中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显示页面。修改web.xml文件,增加以下内容:
Xml代码
1.
2.
3. java.lang.Throwable
4. /500.jsp
5.
6.
7. 500
8. /500.jsp
9.
10.
11. 404
12. /404.jsp
13.
14.
15.
返回状态码
ResponseEntity
ResponseStatus
通过ResponseEntity类返回状态码
在标准的spring mvc Controller中,我们定义简单的映射:
@RequestMapping(value = “/controller”, method = RequestMethod.GET)
@ResponseBody
public ResponseEntity sendViaResponseEntity() {
return new ResponseEntity(HttpStatus.NOT_ACCEPTABLE);
}
一旦收到get 请求 “/controller” ,spring将返回406响应(不可接受)。这里随意选择了一个特定的响应码,你能返回HTTP状态码,完整的状态码参考文档。
通过异常类返回状态码
这里描述第二种方法通过异常类返回状态码:
@RequestMapping(value = “/exception”, method = RequestMethod.GET)
@ResponseBody
public ResponseEntity sendViaException() {
throw new ForbiddenException();
}
当收到get 请求 “/exception”,spring 将抛出ForbiddenException类异常,定义为独立类并增加相应注解:
@ResponseStatus(HttpStatus.FORBIDDEN)
public class ForbiddenException extends RuntimeException {}
1
2
异常类中无需其他相关代码,仅需要@ResponseStatus注解。当抛出异常时,控制器返回403响应码(FORBIDDEN),如果必要,在注解中增加相应消息。
@ResponseStatus(value = HttpStatus.FORBIDDEN, reason=“To show an example of a custom message”)
public class ForbiddenException extends RuntimeException {}