SpringMVC核心

这是我根据自己的理解和网上Simon丶Ma大神的总结,陆陆续续将我自己的理解写在这里,希望大家互相讨论~~~


一、SpringMVC的几个关键步骤:
1、用户向spring发起一个请求
2、请求被DsipatcherServlet拦截,并且交给处理映射器处理
3、处理映射器(HandlerMapping)寻找对应的控制器
4、控制器(Controller)处理后,返回一个ModelAndView(模型和页面)给前端控制器
5、前端控制器去寻找对应的ViewResolver对象解决从控制器返回的视图
6、前端找到对应的页面后,返回给用户,否则抛出异常


二、SpringMVC的角色划分:
1、控制器(Controller)
2、验证器(Validator)
3、命令对象(Object)
4、表单对象(BeanObject)
5、模型对象(Model)
6、分发器(Adapter)
7、处理映射器(HandlerAdapter)
8、视图解析器(ViewResolver)


三、@RequestMapping(),包含4个参数:
value:请求的路径
method:请求的方式
params:请求的参数
headers:请求头


四、@RequestParam(),包含3个参数:
value:参数名
required:是否必需,默认为true
defaultValue:默认参数名,设置该参数时,自动将required设为false。极少情况需要使用该参数,也不推荐使用该参数。


五、在JSP中使用SpringMVC标签:需要在网页头部添加标签支持:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
1.<form>标签:
<form:form action="${ctx}/user/save.${ext}" method="post" commandName="user">
  <table>
  <tr>
 <td>Id:</td>
 <td><form:input path ="id" /></td>
  </tr>
  <tr>
 <td>name:</td>
 <td><form:input path ="name" /></td>
  </tr>
  <tr>
 <td>password:</td>
 <td><form:input path ="password" /></td>
  </tr>
  <tr>
 <td colspan="2"><input type ="submit" value="Save" /></td>
  </tr>
  </table>
</form:form>
必须要与方法中的参数名一样:
@RequestMapping(value="/user/save",method=RequestMethod.GET)
    public String forSave(@ModelAttribute User user){
       return "/index";
    }
2.<input>标签:
<form:input path ="id" />解析后会变成<input id="name" name="name" type="text" value=""/>
3.checkbox标签:
boolean : <td><form:checkbox path="receiveNewsletter"/></td>
String[]: 
            <td>
       Quidditch: <form:checkbox path="interests" value="Quidditch"/>
                Herbology: <form:checkbox path="interests" value="Herbology"/>
                Defence Against the Dark Arts: <form:checkbox path="interests"
                    value="Defence Against the Dark Arts"/>
            </td>
String :  
<td>
                Magic: <form:checkbox path="favouriteWord" value="Magic"/>
            </td>
4.radiobutton标签:单选按钮
<tr> 
<td>Sex:</td> 
<td>Male: <form:radiobutton path="sex" value="M"/> <br/> 
Female: <form:radiobutton path="sex" value="F"/> </td> 
</tr>
5.password标签:密码框
<tr> 
<td>Password:</td> 
<td> 
<form:password path="password" /> 
</td> 
</tr> 
6.select标签:下拉选择框
<tr>
            <td>Skills:</td>
            <td><form:select path="skills" items="${skills}" /></td>
        </tr>
7.option标签:
<form:select path="house"> 
            <form:option value="Gryffindor"/> 
            <form:option value="Hufflepuff"/> 
            <form:option value="Ravenclaw"/> 
            <form:option value="Slytherin"/> 
        </form:select> 
8.options标签:
<form:select path="country"> 
            <form:option value="-" label="--Please Select"/> 
            <form:options items="${countryList}" itemValue="code" itemLabel="name"/> 
        </form:select>
9.textarea标签:
<td><form:textarea path="notes" rows="3" cols="20" /></td> 
10.hidden标签:
<form:hidden path="house" /> 
11.errors标签:
<form:form> 
<table> 
<tr> 
<td>First Name:</td> 
<td><form:input path="firstName" /></td> 
<%-- Show errors for firstName field --%> 
<td><form:errors path="firstName" /></td> 
</tr> 
 
<tr> 
<td>Last Name:</td> 
<td><form:input path="lastName" /></td> 
<%-- Show errors for lastName field --%> 
<td><form:errors path="lastName"  /></td> 
</tr> 
<tr> 
<td colspan="3"> 
<input type="submit" value="Save Changes" /> 
</td> 
</tr> 
</table> 
</form:form> 
六、SpringMVC拦截器:
自定义拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.my.spring.interceptor.myInterceptor">
<property name="xxx" value="xxx"/>
<property name="xxx" value="xxx" />
<property name="xxx" value="xxx" />
</bean>
</mvc:interceptor>
</mvc:interceptors>
七、SpringMVC类型转换:

在实际操作中经常会碰到表单中的日期字符串和Javabean中的日期类型的属性自动转换,而springMVC默认不支持这个格式的转换,所以必须要手动配置,自定义数据类型的绑定才能实现这个功能。

1. 直接将自定义的propertyEditor放到需要处理的java bean相同的目录下
名称和java Bean相同但后面带Editor后缀。
例如需要转换的java bean 名为User,则在相同的包中存在UserEditor类可实现customer propertyEditor的自动注册。

2.利用@InitBinder来注册customer propertyEditor:
public class BaseController {
@InitBinder
public void initBinder(WebDataBinder binder) {
  binder.registerCustomEditor(Date.class, new CustomDateEditor(true));
}
}
3.继承 WebBindingInitializer 接口来实现全局注册:
使用@InitBinder只能对特定的controller类生效,为注册一个全局的customerEditor,可以实现接口WebBindingInitializer:
public class CustomerBinding implements WebBindingInitializer {
public void initBinder(WebDataBinder binder, WebRequest request) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 
                dateFormat.setLenient(false); 
                binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
}
并修改spring-servlet.xml:
<bean  class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
<property name="webBindingInitializer">  
<bean  class="net.zhepu.web.customerBinding.CustomerBinding" />  
</property>  
</bean>  
但这样一来就无法使用mvc:annotation-driven 了。
4.使用conversion-service来注册自定义的converter
DataBinder实现了PropertyEditorRegistry,TypeConverter这两个interface,而在springmvc实际处理时,返回值都是returnbinder.convertIfNecessary(见HandlerMethodInvoker中的具体处理逻辑)。因此可以使用customer
conversionService来实现自定义的类型转换:
<bean id="conversionService" 
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  
<property name="converters"> 
<list> 
<bean class="net.zhepu.web.customerBinding.CustomerConverter" /> 
</list> 


</property> 
</bean> 
需要修改spring-servletxml配置文件中的annotation-driven,增加属性conversion-service指向新增的conversionService bean:
<mvc:annotation-driven validator="validator" conversion-service="conversionService" /> 
5.对于requestBody或httpEntity中数据的类型转换:
SpringMVC中对于requestBody中发送的数据转换不是通过databind来实现,而是使用HttpMessageConverter来实现具体的类型转换。

例如,之前提到的json格式的输入,在将json格式的输入转换为具体的model的过程中,spring mvc首先找出request header中的contenttype,再遍历当前所注册的所有的HttpMessageConverter子类,根据子类中的canRead()方法来决定调用哪个具体的子类来实现对requestBody中的数据的解析。如果当前所注册的httpMessageConverter中都无法解析对应contexttype类型,则抛出 HttpMediaTypeNotSupportedException (http 415错误)。

那么需要如何注册自定义的messageConverter呢,很不幸,在spring3.0.5中如果使用annotation-driven的配置方式的话,无法实现自定义的messageConverter的配置,必须老老实实的自己定义AnnotationMethodHandlerAdapter的bean定义,再设置其messageConverters以注册自定义的 messageConverter。
<mvc:annotation-driven>  
<mvc:message-converters>  
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>  
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>  
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>  
</mvc:message-converters>  
</mvc:annotation-driven>
八、JSON格式数据的输入和输出:
首先是依赖包:
dependency>
           <groupId>org.codehaus.jackson</groupId>
           <artifactId>jackson-core-lgpl</artifactId>
           <version>1.8.0</version>
           <scope>compile</scope>
       </dependency>
       <dependency>
           <groupId>org.codehaus.jackson</groupId>
           <artifactId>jackson-mapper-asl</artifactId>
           <version>1.8.0</version>
</dependency>
输入:
1.使用@RequestBody来设置输入:
@RequestMapping("/json1")
@ResponseBody
public JsonResult testJson1(@RequestBody User u){
log.info("get json input from request body annotation");
log.info(u.getUserName());
return new JsonResult(true,"return ok");
}
2.使用HttpEntity来实现输入绑定:
@RequestMapping("/json2")
public ResponseEntity<JsonResult> testJson2(HttpEntity<User> u){
log.info("get json input from HttpEntity annotation");
log.info(u.getBody().getUserName());
ResponseEntity<JsonResult> responseResult = new ResponseEntity<JsonResult>(new JsonResult(true,"return ok"),HttpStatus.OK);
return responseResult;
}
输出:
1.使用@responseBody来设置输出内容为context body:
@RequestMapping(value="/kfc/brands/{name}", method = RequestMethod.GET)
public @ResponseBody List<Shop> getShopInJSON(@PathVariable String name) {
  List<Shop> shops = new ArrayList<Shop>();
  Shop shop = new Shop();
  shop.setName(name);
  shop.setStaffName(new String[]{"mkyong1", "mkyong2"}); 
  shops.add(shop);
  Shop shop2 = new Shop();
  shop2.setName(name);
  shop2.setStaffName(new String[]{"mktong1", "mktong2"});
  shops.add(shop2);
  return shops;
}
2.返回值设置为ResponseEntity<?>类型,以返回context body:
@RequestMapping("/json2")
public ResponseEntity<JsonResult> testJson2(HttpEntity<User> u){
log.info("get json input from HttpEntity annotation");
log.info(u.getBody().getUserName());
ResponseEntity<JsonResult> responseResult = new ResponseEntity<JsonResult>( new JsonResult(true,"return ok"),HttpStatus.OK);
return responseResult;
}
九、SpringMVC文件上传:Spring mvc使用jakarta的commons fileupload来支持文件上传。
首先也是依赖包:
<dependency> 
<groupId>commons-io</groupId> 
<artifactId>commons-io</artifactId> 
<version>2.0.1</version> 
       </dependency>         
<dependency> 
<groupId>commons-fileupload</groupId> 
<artifactId>commons-fileupload</artifactId> 
<version>1.2.2</version> 
</dependency> 
在spring-servlet.xml中加入以下这段代码:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000" />
</bean> 
在jsp页面中,也就是客户端中:
<form method="post" action="${ctx}/user/upload.${ext}" enctype="multipart/form-data">
<input type="text" name="name"/>
<input type="file" name="file"/>
<input type="submit"/>
</form>
在服务器端中:
@RequestMapping(value = "/user/upload", method = RequestMethod.POST)
public String handleFormUpload(@RequestParam("name") String name,
           @RequestParam("file") MultipartFile file, HttpServletRequest request)
           throws IOException {
  String filePath = request.getRealPath("/");
  if (!file.isEmpty()) {
  String fileName = file.getOriginalFilename();
  System.out.println(filePath + "/" + fileName);
  byte[] bytes = file.getBytes();
  FileOutputStream output = new FileOutputStream(new File(filePath
 + fileName));
  output.write(bytes);
  output.close();
  return "redirect:/success.jsp";
  } else {
  return "redirect:/failure.jsp";
  }
}
十、SpringMVC国际化和本地化:实现三种语言可以相互切换的国际化和本地化:
1.在resources下创建3个property文件,分别为:message_de.properties、message_en.properties、message_zh.properties
(文件的命名规则:message_语言.properties),文件的内容如下:
messages_de.properties
label.firstname=Vorname
label.lastname=Familiename
label.email=Email
label.telephone=Telefon
label.addcontact=Addieren Kontakt
label.title=spring mvc Internationalization (i18n) / Localization
messages_en.properties
label.firstname=First Name
label.lastname=Last Name
label.email=Email
label.telephone=Telephone
label.addcontact=Add Contact
label.title=spring mvc Internationalization (i18n) / Localization
messages_zh.properties(经过转换后的中文)
label.firstname=\u59D3
label.lastname=\u540D\u5B57
label.email=\u7535\u5B50\u90AE\u4EF6
label.telephone=\u7535\u8BDD
label.addcontact=\u8054\u7CFB\u65B9\u5F0F
label.title=spring mvc \u56FD\u9645\u5316\u548C\u672C\u5730\u5316\u652F\u6301
2.spring-servlet.xml配置:为了使用国际化信息源,SpringMVC必须实现MessageSource接口。当然框架内部有许多内置的实现类。我们需要做的是注册一个MessageSource类型的Bean。Bean的名称必须为messageSource,从而方便DispatcherServlet自动检测它。每个DispatcherServlet只能注册一个信息源:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
  <property name="basename" value="classpath:messages" />
  <property name="defaultEncoding" value="UTF-8" />
</bean>
<!—session 解析区域 -->
    <bean id="localeResolver" 
        class="org.springframework.web.servlet.i18n.SessionLocaleResolver">     
<!-- property name="defaultLocale" value="en"/> --> 
    </bean> 
 <!-- 修改用户的区域需要调用区域修改拦截器LocaleChangeInterceptor。如下所设定设定paramName属性来设定拦截请求中的特定参数(这里是language)确定区域。既然是拦截器那就需要注册到拦截器Bean中,这里是注册到了DefaultAnnotationHandlerMapping Bean中 -->
    <bean id="localeChangeInterceptor"
       class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
       <property name="paramName" value="lang" />
    </bean>
<!--
    <bean id="localeResolver"
       class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
       <property name="defaultLocale" value="en" />
    </bean>
 -->
    <bean id="handlerMapping"
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
       <property name="interceptors">
           <ref bean="localeChangeInterceptor" />
       </property>
    </bean>

3.创建contact.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
    <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<c:set var="ext" value="html" />
<html>
<head>
<title>Spring 3 MVC Series - Contact Manager</title>
</head>
<body>
<h3><spring:message code="label.title"/></h3>
<span style="float: right">
<a href="${ctx}/language.${ext}?local=en">英文</a>
|
<a href="${ctx}/language.${ext}?local=de">德文</a>
|
<a href="${ctx}/language.${ext}?local=zh">中文</a>
</span>
<form:form method="post" action="addContact.html" commandName="contact">
<table>
<tr>
  <td><form:label path="firstname"><spring:message code="label.firstname"/></form:label></td>
  <td><form:input path="firstname" /></td>
</tr>
<tr>
  <td><form:label path="lastname"><spring:message code="label.lastname"/></form:label></td>
  <td><form:input path="lastname" /></td>
</tr>
<tr>
  <td><form:label path="lastname"><spring:message code="label.email"/></form:label></td>
  <td><form:input path="email" /></td>
</tr>
<tr>
  <td><form:label path="lastname"><spring:message code="label.telephone"/></form:label></td>
<td><form:input path="telephone" /></td>
</tr>
<tr>
  <td colspan="2">
  <input type="submit" value="<spring:message code="label.addcontact"/>"/>
  </td>
</tr>
</table>   
</form:form>
</body>
</html>
其中<spring:message>标签结合 ResourceBundleMessageSource 的功能,在网页上显示 messages.properties 中的文字讯息。
4.创建LanguageController
@Controller
public class LanguageController {
@Autowired
private SessionLocaleResolver localeResolver;
@RequestMapping("/forLanguage")
public String forLanguage(@ModelAttribute Contact contact){
  return "/contact";
}
@RequestMapping(value="/language",method=RequestMethod.GET)
public ModelAndView changeLocal(@ModelAttribute Contact contact,HttpServletRequest request,@RequestParam String local,HttpServletResponse response){ 
if("zh".equals(local)){  
localeResolver.setLocale(request, response, Locale.CHINA); 
}else if("en".equals(local))  {
localeResolver.setLocale(request, response, Locale.ENGLISH); 
}else if("de".equals(local)){
localeResolver.setLocale(request, response, Locale.GERMAN);
}  
return new ModelAndView("/contact"); 

}
十一、使用jsr303进行验证:
private Long id;
@Size(min = 1, message = "自定义错误信息:姓氏长度必须大于1")
private String firstName;
@NotNull
@Size(min = 1, message = "自定义错误信息:名字长度必须大于1")
private String lastName;
@Past(message = "自定义错误信息:出生日期必须是在现在的时间之前")
private Date birth;
private Boolean married;
@Min(value = 0, message = "孩子数量最少为0")
@Max(value = 20, message = "孩子数量最大为20")
private int children;
jsr303的常用注解:
表 1. Bean Validation 中内置的 constraint
注    解                功能说明
@Null                   被注释的元素必须为 null
@NotNull                被注释的元素必须不为 null
@AssertTrue             被注释的元素必须为 true
@AssertFalse   被注释的元素必须为 false
@Min(value)   被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)   被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)      被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)      被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)         被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past                   被注释的元素必须是一个过去的日期
@Future                 被注释的元素必须是一个将来的日期
@Pattern(value)         被注释的元素必须符合指定的正则表达式
 
表 2. Hibernate Validator 附加的 constraint
 
@Email                    被注释的元素必须是电子邮箱地址
@Length                   被注释的字符串的大小必须在指定的范围内
@NotEmpty                 被注释的字符串的必须非空
@Range                    被注释的元素必须在合适的范围内
自定义注解:
@Age部分

public @interface Age {
String message() default "年龄填写不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Status部分

@Constraint(validatedBy = { StatusValidator.class })
@Documented
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
String message() default "状态选择不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

public class StatusValidator implements ConstraintValidator<Status, Integer> {
private final int[] ALL_STATUS = { 1, 2, 3 };


public void initialize(Status arg0) {
// TODO Auto-generated method stub


}


public boolean isValid(Integer arg0, ConstraintValidatorContext arg1) {
if (Arrays.asList(ALL_STATUS).contains(arg0)) {
return true;
} else {
return false;
}
}
}
使用,在属性上增加age、status
@Age
private int age;
@Status
private int status;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值