SpringMvc 深入讲解 二

来源:互联网 发布:ubuntu kylin安装教程 编辑:程序博客网 时间:2024/06/05 21:13

SpringMvc 深入讲解 二

  简介:技术点:@ModelAttribute中实现CRUD(将post转换delete put请求)、数据类型转换(自定义类型转换器)以及数据格式校验并将错误信息展示、发布数据(Json xml 文件下载)响应控制、国际化(不通过浏览器设置)、异常处理及其展示信息、拦截器讲解

1.项目清单

 

2.顺序源码与解读

package com.atguigu.springmvc.converters;import org.springframework.core.convert.converter.Converter;import org.springframework.stereotype.Component;import com.atguigu.springmvc.crud.entities.Department;import com.atguigu.springmvc.crud.entities.Employee;/** * 1.自定义类型转换器,比如在表单中请求epms的时候 ,提交的数据格式是//GG-gg@atguigu.com-0-105 * 就会返回一个Employee类型的bean,而在请求的方法参数中这样写(@RequestParam(value="表单name") Employee employee) * 在强制转换的时候就会使用该转换器 * 2.配置转换器 在xml中有详细讲解 */@Componentpublic class EmployeeConverter implements Converter<String, Employee> {public Employee convert(String source) {if(source != null){String [] vals = source.split("-");//GG-gg@atguigu.com-0-105if(vals != null && vals.length == 4){String lastName = vals[0];String email = vals[1];Integer gender = Integer.parseInt(vals[2]);Department department = new Department();department.setId(Integer.parseInt(vals[3]));Employee employee = new Employee(null, lastName, email, gender, department);System.out.println(source + "--convert--" + employee);return employee;}}return null;}}
package com.atguigu.springmvc.crud.dao;import java.util.Collection;import java.util.HashMap;import java.util.Map;import org.springframework.stereotype.Repository;import com.atguigu.springmvc.crud.entities.Department;@Repositorypublic class DepartmentDao {private static Map<Integer, Department> departments = null;static{departments = new HashMap<Integer, Department>();departments.put(101, new Department(101, "D-AA"));departments.put(102, new Department(102, "D-BB"));departments.put(103, new Department(103, "D-CC"));departments.put(104, new Department(104, "D-DD"));departments.put(105, new Department(105, "D-EE"));}public Collection<Department> getDepartments(){return departments.values();}public Department getDepartment(Integer id){return departments.get(id);}}
package com.atguigu.springmvc.crud.dao;import java.util.Collection;import java.util.HashMap;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import com.atguigu.springmvc.crud.entities.Department;import com.atguigu.springmvc.crud.entities.Employee;@Repositorypublic class EmployeeDao {private static Map<Integer, Employee> employees = null;@Autowiredprivate DepartmentDao departmentDao;static{employees = new HashMap<Integer, Employee>();employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA")));employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB")));employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC")));employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD")));employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE")));}private static Integer initId = 1006;public void save(Employee employee){if(employee.getId() == null){employee.setId(initId++);}employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));employees.put(employee.getId(), employee);}public Collection<Employee> getAll(){return employees.values();}public Employee get(Integer id){return employees.get(id);}public void delete(Integer id){employees.remove(id);}}
package com.atguigu.springmvc.crud.entities;public class Department {private Integer id;private String departmentName;public Department() {// TODO Auto-generated constructor stub}public Department(int i, String string) {this.id = i;this.departmentName = string;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getDepartmentName() {return departmentName;}public void setDepartmentName(String departmentName) {this.departmentName = departmentName;}@Overridepublic String toString() {return "Department [id=" + id + ", departmentName=" + departmentName+ "]";}}
package com.atguigu.springmvc.crud.entities;import java.util.Date;import javax.validation.Valid;import javax.validation.constraints.Past;import org.hibernate.validator.constraints.Email;import org.hibernate.validator.constraints.NotEmpty;import org.springframework.format.annotation.DateTimeFormat;import org.springframework.format.annotation.NumberFormat;public class Employee {private Integer id;@NotEmptyprivate String lastName;@Emailprivate String email;//1 male, 0 femaleprivate Integer gender;private Department department;@Past@DateTimeFormat(pattern="yyyy-MM-dd")private Date birth;/** * 类型转换要在springmvc.xml中配置才能使用 * 1.配置 ConversionService 自定义类型转换器 * class=org.springframework.format.support.FormattingConversionServiceFactoryBean即可以实现@DateTimeFormat等        这样的数据格式转换,同时也支持了自定义的类型转换器   class=org.springframework.context.support.ConversionServiceFactoryBean和上述的一样,只是上面的类中支持更多数据格式化配置          <mvc:annotation-driven/>这个标签自动配置了org.springframework.context.support.ConversionServiceFactoryBean       如果有定义了自己的类型转换器,加入conversion-service="conversionService"属性即可       以上两种都支持@DateTimeFormat等数据格式化配置,只是上一中支持的更多                 2.区分  @Past 和  @DateTimeFormat(pattern="yyyy-MM-dd")前者是jsr 数据校验,后者是数据格式化              数据校验的时候呢在需要校验的参数前面加上@Valid             数据校验和数据格式化(类型转换)的错误内容都可以使用BindingResult 或者 Errors来承接,需要以下注意点:             1.BindingResult 必须是在要数据格式化的参数后面出现,两者中间不能有别的参数             2.BindingResult 数据格式化的参数必须在@ModelAttribute中出现过,一般确定数据格式 user                 */@NumberFormat(pattern="#,###,###.#")private Float salary;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Integer getGender() {return gender;}public void setGender(Integer gender) {this.gender = gender;}public Department getDepartment() {return department;}public void setDepartment(Department department) {this.department = department;}public Date getBirth() {return birth;}public void setBirth(Date birth) {this.birth = birth;}public Float getSalary() {return salary;}public void setSalary(Float salary) {this.salary = salary;}@Overridepublic String toString() {return "Employee [id=" + id + ", lastName=" + lastName + ", email="+ email + ", gender=" + gender + ", department=" + department+ ", birth=" + birth + ", salary=" + salary + "]";}public Employee(Integer id, String lastName, String email, Integer gender,Department department) {super();this.id = id;this.lastName = lastName;this.email = email;this.gender = gender;this.department = department;}public Employee() {// TODO Auto-generated constructor stub}}
package com.atguigu.springmvc.crud.handlers;import java.io.IOException;import java.io.InputStream;import java.util.Locale;import java.util.Map;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import javax.validation.Valid;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cglib.core.Local;import org.springframework.context.support.ResourceBundleMessageSource;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import com.atguigu.springmvc.crud.dao.DepartmentDao;import com.atguigu.springmvc.crud.dao.EmployeeDao;import com.atguigu.springmvc.crud.entities.Department;import com.atguigu.springmvc.crud.entities.Employee;@Controllerpublic class EmployeeHandler {@Autowiredprivate EmployeeDao employeeDao;@Autowiredprivate ResourceBundleMessageSource rms;@Autowiredprivate DepartmentDao departmentDao;@ModelAttributepublic void getEmployee(@RequestParam(value="id",required=false) Integer id,Map<String, Object> map){if(id != null){map.put("employee", employeeDao.get(id));}}@RequestMapping(value="/emp", method=RequestMethod.PUT)public String update(Employee employee){employeeDao.save(employee);return "redirect:/emps";}@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)public String input(@PathVariable("id") Integer id, Map<String, Object> map){map.put("employee", employeeDao.get(id));map.put("departments", departmentDao.getDepartments());return "input";}@RequestMapping(value="/emp/{id}", method=RequestMethod.DELETE)public String delete(@PathVariable("id") Integer id){employeeDao.delete(id);return "redirect:/emps";}/** * 类型转换失败的信息可以用BindingResult result来显示 * BindingResult 必须是在要数据格式化的参数后面出现 * BindingResult 数据格式化的参数必须在@ModelAttribute中出现过,一般确定数据格式 user */@RequestMapping(value="/emp", method=RequestMethod.POST)public String save(@Valid Employee employee, BindingResult result, Map<String, Object> map){System.out.println("save: " + employee);if(result.getErrorCount() > 0){System.out.println("出错了!");for(FieldError error:result.getFieldErrors()){System.out.println(error.getField() + ":" + error.getDefaultMessage());}//若验证出错, 则转向定制的页面map.put("departments", departmentDao.getDepartments());return "input";}employeeDao.save(employee);return "redirect:/emps";}@RequestMapping(value="/emp", method=RequestMethod.GET)public String input(Map<String, Object> map){map.put("departments", departmentDao.getDepartments());map.put("employee", new Employee());return "input";}@RequestMapping("/emps")public String list(Map<String, Object> map){map.put("employees", employeeDao.getAll());System.out.println(employeeDao.getAll().size());return "list";}//哪一个字段值是从表单不进行赋值的//@InitBinder//public void initBinder(WebDataBinder binder){//binder.setDisallowedFields("lastName");//}/** * 请求和相应的格式转换 两种方式 -----------------在MyJsp中写入了测试 * @RequestBody @ResponseBody     HttpEntity ResponseEntity * 他们会根据返回的java类型而对客户端响应  例如 如果返回list 等数组,会转换位json等数据 * 如果想要实现在页面上发布json xml等数据格式,或者是形成一个下载流,使用ResponseEntity来实现 */@ResponseBody@RequestMapping("/testOut1")public String testOut1(){return "你好,这种方式相当于是用printWrite.write()方法写入的";}/** *  */@ResponseBody@RequestMapping("/testOut2")public Department testOut2(HttpServletResponse resp){//自动的就转换为了Json数据格式了 Bean list 这些会被转换位Jsonreturn new Department(1, "message");}/** * 页面输出了xml数据 * @throws IOException  */@RequestMapping("/testOut4")public ResponseEntity<byte[]> testOut4() throws IOException{byte [] body = null;body = new EmployeeHandler().getXmlInfo().getBytes();HttpHeaders headers = new HttpHeaders();MediaType mediaType = MediaType.APPLICATION_XML;headers.setContentType(mediaType);HttpStatus statusCode = HttpStatus.OK;ResponseEntity<byte[]> res = new ResponseEntity<byte[]>(body, headers, statusCode);    return res;}/** * 输入一个下载的格式数据 * @throws IOException  */@RequestMapping("/testOut3")public ResponseEntity<byte[]> download(HttpSession session) throws IOException{byte [] body = null;ServletContext servletContext = session.getServletContext();InputStream in = servletContext.getResourceAsStream("/files/abc.txt");body = new byte[in.available()];in.read(body);HttpHeaders headers = new HttpHeaders();headers.add("Content-Disposition", "attachment;filename=abc.txt");HttpStatus statusCode = HttpStatus.OK;ResponseEntity<byte[]> res = new ResponseEntity<byte[]>(body, headers, statusCode);    return res;}         /** * 通过超链接进行国际化 * 1.在这里注入private ResourceBundleMessageSource rms;   2. 在 bean 中注入 ResourceBundleMessageSource 的示例, 使用其对应的 getMessage 方法即可   3. 配置 LocalResolver 和 LocaleChangeInterceptor拦截器 本例中使用的是 SessionLocaleResolver,并在              连接中写入?locale=zh_CH */        @RequestMapping("/gjh")public String gjh1(Locale locale){System.out.println(rms.getMessage("i18n.user", null, locale));return "i18n";}private String getXmlInfo() {     StringBuilder sb = new StringBuilder();      sb.append("<videoSend>");      sb.append("<header>");      sb.append("<sid>1</sid>");      sb.append("<type>service</type>");     sb.append("</header>");      sb.append("<service name=\"videoSend\">");     sb.append("<fromNum>0000021000011001</fromNum>");      sb.append("<toNum>33647405</toNum>");      sb.append("<videoPath>mnt/5.0.217.50/resources/80009.mov</videoPath>");      sb.append("<chargeNumber>0000021000011001</chargeNumber>");     sb.append("</service>");      sb.append("</videoSend>");      return sb.toString();  }  /**   异常处理:注意 该方法是异常的承接只配置了@ExceptionHandler 而没有配置@RequestMapping 它只是要捕获异常*                                                                                           * 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象  * 2. @ExceptionHandler 方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值  * 3. @ExceptionHandler 方法标记的异常有优先级的问题.   * 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常,   *    则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.  * 5. 下面的定义只是在该handler中的方法有异常会处理,并不是全局,SpringMVCTestExceptionHandler 这个是定义了全局          @ResponseStatus 无论怎样都会进入配置的页面中,可以使用到异常出,让其有异常时进入  */ <a>//@ResponseStatus(value=HttpStatus.FORBIDDEN</a>, reason="用户名和密码不匹配!") @ExceptionHandler({ArithmeticException.class}) public ModelAndView handleArithmeticException(Exception ex){  System.out.println("出异常了: " + ex);  ModelAndView mv = new ModelAndView("error");  mv.addObject("exception", ex);  return mv; } /**  * 没有发生异常将正常执行 如果发生异常将按照上面的执行  */  @RequestMapping("showException") public String showException(@RequestParam("i") int i) {  System.out.println("--? result :" + 10 / i);  return "success"; }}
package com.atguigu.springmvc.test;import java.io.IOException;import java.io.InputStream;import java.util.Collection;import java.util.Date;import java.util.Locale;import java.util.Map;import javax.servlet.ServletContext;import javax.servlet.http.HttpSession;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.support.ResourceBundleMessageSource;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.ResponseStatus;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.servlet.ModelAndView;import com.atguigu.springmvc.crud.dao.EmployeeDao;import com.atguigu.springmvc.crud.entities.Employee;@Controllerpublic class SpringMVCTest {@Autowiredprivate EmployeeDao employeeDao;@Autowiredprivate ResourceBundleMessageSource messageSource;@RequestMapping("/testSimpleMappingExceptionResolver")public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){String [] vals = new String[10];System.out.println(vals[i]);return "success";}@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)public String testDefaultHandlerExceptionResolver(){System.out.println("testDefaultHandlerExceptionResolver...");return "success";}    /**     * 方法上标示@ResponseStatus 不管是否抛出异常都会进入异常页面     */@ResponseStatus(reason="测试",value=HttpStatus.NOT_FOUND)@RequestMapping("/testResponseStatusExceptionResolver")public String testResponseStatusExceptionResolver(@RequestParam("i") int i){if(i == 13){throw new UserNameNotMatchPasswordException();}System.out.println("testResponseStatusExceptionResolver...");return "success";}//@ExceptionHandler({RuntimeException.class})//public ModelAndView handleArithmeticException2(Exception ex){//System.out.println("[出异常了]: " + ex);//ModelAndView mv = new ModelAndView("error");//mv.addObject("exception", ex);//return mv;//}/** * 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象 * 2. @ExceptionHandler 方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值 * 3. @ExceptionHandler 方法标记的异常有优先级的问题.  * 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常,  * 则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.  *///@ExceptionHandler({ArithmeticException.class})//public ModelAndView handleArithmeticException(Exception ex){//System.out.println("出异常了: " + ex);//ModelAndView mv = new ModelAndView("error");//mv.addObject("exception", ex);//return mv;//}@RequestMapping("/testExceptionHandlerExceptionResolver")public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i){System.out.println("result: " + (10 / i));return "success";}@RequestMapping("/testFileUpload")public String testFileUpload(@RequestParam("desc") String desc, @RequestParam("file") MultipartFile file) throws IOException{System.out.println("desc: " + desc);System.out.println("OriginalFilename: " + file.getOriginalFilename());System.out.println("InputStream: " + file.getInputStream());return "success";}@RequestMapping("/i18n")public String testI18n(Locale locale){String val = messageSource.getMessage("i18n.user", null, locale);System.out.println(val); return "i18n";}@RequestMapping("/testResponseEntity")public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{byte [] body = null;ServletContext servletContext = session.getServletContext();InputStream in = servletContext.getResourceAsStream("/files/abc.txt");body = new byte[in.available()];in.read(body);HttpHeaders headers = new HttpHeaders();headers.add("Content-Disposition", "attachment;filename=abc.txt");HttpStatus statusCode = HttpStatus.OK;ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body, headers, statusCode);return response;}@ResponseBody@RequestMapping("/testHttpMessageConverter")public String testHttpMessageConverter(@RequestBody String body){System.out.println(body);return "helloworld! " + new Date();}@ResponseBody@RequestMapping("/testJson")public Collection<Employee> testJson(){return employeeDao.getAll();}@RequestMapping("/testConversionServiceConverer")public String testConverter(@RequestParam("employee") Employee employee){System.out.println("save: " + employee);employeeDao.save(employee);return "redirect:/emps";}}

 

package com.atguigu.springmvc.test;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.servlet.ModelAndView;/** * 全局的异常处理问题 */@ControllerAdvicepublic class SpringMVCTestExceptionHandler {@ExceptionHandler({ArithmeticException.class})public ModelAndView handleArithmeticException(Exception ex){System.out.println("----> 出异常了: " + ex);ModelAndView mv = new ModelAndView("error");mv.addObject("exception", ex);return mv;}}
package com.atguigu.springmvc.test;import org.springframework.http.HttpStatus;import org.springframework.web.bind.annotation.ResponseStatus;/** * 当抛出出现异常时,定制自己的状态页面 */@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="用户名和密码不匹配!")public class UserNameNotMatchPasswordException extends RuntimeException{/** *  */private static final long serialVersionUID = 1L;}


异常处理第二种方式

package com.lives.manage.web.handler;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerExceptionResolver;import org.springframework.web.servlet.ModelAndView;import com.lives.manage.common.exception.ResourceNotFoundException;import com.lives.manage.common.exception.ServiceException;/** * 配置component 让spring识别为异常处理类: * HandlerExceptionResolver 和  sim。。。。 * 所有抛出的异常处理类 */@Componentpublic class CatchExeceptionHandler implements HandlerExceptionResolver {private static final Logger logger = Logger.getLogger(CatchExeceptionHandler.class);@Overridepublic ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) {/** * 如果为自定义异常类,单独进行处理 */int status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;if(ex instanceof ServiceException){ServiceException se = (ServiceException)ex;logger.error(se);} else {logger.error("system exception: ", ex);if (ex instanceof ResourceNotFoundException) {status = HttpServletResponse.SC_NOT_FOUND;}}String ajaxHeader = request.getHeader("isAjax");boolean isAjax = ajaxHeader != null && "1".equals(ajaxHeader);if (isAjax) {response.setStatus(status);try {response.flushBuffer();} catch (IOException e) {}return null;}ModelAndView mav = new ModelAndView();mav.addObject("status", status);mav.setViewName("error/serv");return mav;}}


 

3.springmvc.xml 配置讲解

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"><!-- 配置自动扫描的包 --><context:component-scan base-package="com.atguigu.springmvc"></context:component-scan><!-- 配置视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"></property><property name="suffix" value=".jsp"></property></bean><!--  default-servlet-handler 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查, 如果发现是没有经过映射的请求, 就将该请求交由 WEB 应用服务器默认的 Servlet 处理. 如果不是静态资源的请求,才由 DispatcherServlet 继续处理一般 WEB 应用服务器默认的 Servlet 的名称都是 default.若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定--><mvc:default-servlet-handler/><mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven><!-- 配置 ConversionService 自定义类型转换器class=org.springframework.format.support.FormattingConversionServiceFactoryBean即可以实现@DateTimeFormat等这样的数据格式转换,同时也支持了自定义的类型转换器class=org.springframework.context.support.ConversionServiceFactoryBean<mvc:annotation-driven/>这个标签自动配置了org.springframework.context.support.ConversionServiceFactoryBean如果有定义了自己的类型转换器,加入conversion-service="conversionService"属性即可以上两种都支持@DateTimeFormat等数据格式化配置,只是上一中支持的更多--><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><set><ref bean="employeeConverter"/></set></property></bean><!-- 配置国际化资源文件 --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="i18n"></property></bean><!-- 配置 SessionLocalResolver --><bean id="localeResolver"class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>        <mvc:interceptors><!-- 配置 LocaleChanceInterceptor 只有上面的一个配置无法实现国际化--><bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" ></bean></mvc:interceptors>        <!-- 配置 MultipartResolver --><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="defaultEncoding" value="UTF-8"></property><property name="maxUploadSize" value="1024000"></property></bean><!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 --><bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionAttribute" value="ex"></property><property name="exceptionMappings"><props><prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop></props></property></bean><mvc:view-controller path="/i18n2" view-name="i18n2"/></beans>

 

4.web.xml 配置讲解

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID" version="2.5"><!-- 配置 SpringMVC 的 DispatcherServlet --><!-- The front controller of this Spring Web application, responsible for handling all application requests --><servlet><servlet-name>springDispatcherServlet</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><load-on-startup>1</load-on-startup></servlet><!-- Map all requests to the DispatcherServlet for handling --><servlet-mapping><servlet-name>springDispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 配置 HiddenHttpMethodFilter: 把 POST 请求转为 DELETE、PUT 请求 --><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></web-app>

 

5.properties 配置错误信息以及国际化(顺序展示)

NotEmpty.employee.lastName=^^LastName\u4E0D\u80FD\u4E3A\u7A7A.Email.employee.email=Email\u5730\u5740\u4E0D\u5408\u6CD5Past.employee.birth=Birth\u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4. typeMismatch.employee.birth=Birth\u4E0D\u662F\u4E00\u4E2A\u65E5\u671F. i18n.user=Useri18n.password=Password
NotEmpty.employee.lastName=^^LastName\u4E0D\u80FD\u4E3A\u7A7A.Email.employee.email=Email\u5730\u5740\u4E0D\u5408\u6CD5Past.employee.birth=Birth\u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4. typeMismatch.employee.birth=Birth\u4E0D\u662F\u4E00\u4E2A\u65E5\u671F. i18n.user=\u7528\u6237\u540Di18n.password=\u5BC6\u7801
NotEmpty.employee.lastName=^^LastName\u4E0D\u80FD\u4E3A\u7A7A.Email.employee.email=Email\u5730\u5740\u4E0D\u5408\u6CD5Past.employee.birth=Birth\u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4. typeMismatch.employee.birth=Birth\u4E0D\u662F\u4E00\u4E2A\u65E5\u671F. i18n.user=Useri18n.password=Password

 

6.问题分析

在展示错误信息的时候,可能会有包的冲突问题,下列给出了解决方案

7.jsp 页面(顺序展示)

①list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title><!--  SpringMVC 处理静态资源:1. 为什么会有这样的问题:优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀若将 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。2. 解决: 在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/>--><script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script><script type="text/javascript">$(function(){$(".delete").click(function(){var href = $(this).attr("href");$("form").attr("action", href).submit();return false;});})</script></head><body><form action="" method="POST"><input type="hidden" name="_method" value="DELETE"/></form><c:if test="${empty requestScope.employees }">没有任何员工信息.</c:if><c:if test="${!empty requestScope.employees }"><table border="1" cellpadding="10" cellspacing="0"><tr><th>ID</th><th>LastName</th><th>Email</th><th>Gender</th><th>Department</th><th>Edit</th><th>Delete</th></tr><c:forEach items="${requestScope.employees }" var="emp"><tr><td>${emp.id }</td><td>${emp.lastName }</td><td>${emp.email }</td><td>${emp.gender == 0 ? 'Female' : 'Male' }</td><td>${emp.department.departmentName }</td><td><a href="emp/${emp.id}">Edit</a></td><td><a class="delete" href="emp/${emp.id}">Delete</a></td></tr></c:forEach></table></c:if><br><br><a href="emp">Add New Employee</a></body></html>

②input.jsp

<%@page import="java.util.HashMap"%><%@page import="java.util.Map"%><%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body>    <!-- 自定义类型转换器 --><form action="testConversionServiceConverer" method="POST"><!-- lastname-email-gender-department.id 例如: GG-gg@atguigu.com-0-105 -->Employee: <input type="text" name="employee"/><input type="submit" value="Submit"/></form><br><br><!--  1. WHY 使用 form 标签呢 ?可以更快速的开发出表单页面, 而且可以更方便的进行表单值的回显2. 注意:必须通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean如果该属性值也不存在,则会发生错误。--><br><br><form:form action="${pageContext.request.contextPath }/emp" method="POST" modelAttribute="employee"><form:errors path="*"></form:errors><br><c:if test="${employee.id == null }"><!-- path 属性对应 html 表单标签的 name 属性值 -->LastName: <form:input path="lastName"/><form:errors path="lastName"></form:errors></c:if><c:if test="${employee.id != null }"><form:hidden path="id"/><input type="hidden" name="_method" value="PUT"/><%-- 对于 _method 不能使用 form:hidden 标签, 因为 modelAttribute 对应的 bean 中没有 _method 这个属性 --%><%-- <form:hidden path="_method" value="PUT"/>--%></c:if><br>Email: <form:input path="email"/><form:errors path="email"></form:errors><br><% Map<String, String> genders = new HashMap();genders.put("1", "Male");genders.put("0", "Female");request.setAttribute("genders", genders);%>Gender: <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br>Department: <form:select path="department.id" items="${departments }" itemLabel="departmentName" itemValue="id"></form:select><br><!--  1. 数据类型转换         配置类型转换器 <mvc:annotation-driven ></mvc:annotation-driven>自动配置好了一个2. 数据类型格式化@DateTimeFormat(pattern="yyyy-MM-dd")3. 数据校验. 1). 如何校验 ? 注解 ?①. 使用 JSR 303 验证标准②. 加入 hibernate validator 验证框架的 jar 包③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />④. 需要在 bean 的属性上添加对应的注解⑤. 在目标方法 bean 类型的前面添加 @Valid 注解2). 验证出错转向到哪一个页面 ?注意: 需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参3). 错误消息 ? 如何显示, 如何把错误消息进行国际化    配置国际化资源文件,写入校验名.bean名.属性名 比如NotEmpty.employee.lastName-->Birth: <form:input path="birth"/><form:errors path="birth"></form:errors><br>Salary: <form:input path="salary"/><br><input type="submit" value="Submit"/></form:form></body></html>

③i18n.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body>        <!--  关于国际化:1. 在页面上能够根据浏览器语言设置的情况对文本(不是内容), 时间, 数值进行本地化处理2. 可以在 bean 中获取国际化资源文件 Locale 对应的消息3. 可以通过超链接切换 Locale, 而不再依赖于浏览器的语言设置情况相对应解决:1. 使用 JSTL 的 fmt 标签---ResourceBundleMessageSource2. 在 bean 中注入 ResourceBundleMessageSource 的示例, 使用其对应的 getMessage 方法即可3. 配置 LocalResolver 和 LocaleChangeInterceptor拦截器 本例中使用的是 SessionLocaleResolver,并在       连接中写入?locale=zh_CH--><fmt:message key="i18n.user"></fmt:message><br><br><a href="i18n2">I18N2 PAGE</a><br><br><a href="gjh?locale=zh_CH">中文</a><br><br><a href="gjh?locale=en_US">英文</a></body></html>

④i18n2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body><fmt:message key="i18n.password"></fmt:message><br><br><a href="i18n">I18N PAGE</a></body></html>

⑤index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title><script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script><script type="text/javascript">$(function(){$("#testJson").click(function(){var url = this.href;var args = {};$.post(url, args, function(data){for(var i = 0; i < data.length; i++){var id = data[i].id;var lastName = data[i].lastName;alert(id + ": " + lastName);}});return false;});})</script></head><body><form action="testFileUpload" method="POST" enctype="multipart/form-data">File: <input type="file" name="file"/>Desc: <input type="text" name="desc"/><input type="submit" value="Submit"/></form><br><br><a href="emps">List All Employees</a><br><br><a href="testJson" id="testJson">Test Json</a><br><br><form action="testHttpMessageConverter" method="POST" enctype="multipart/form-data">File: <input type="file" name="file"/>Desc: <input type="text" name="desc"/><input type="submit" value="Submit"/></form><br><br><a href="testResponseEntity">Test ResponseEntity</a><!--  关于国际化:1. 在页面上能够根据浏览器语言设置的情况对文本(不是内容), 时间, 数值进行本地化处理2. 可以在 bean 中获取国际化资源文件 Locale 对应的消息3. 可以通过超链接切换 Locale, 而不再依赖于浏览器的语言设置情况解决:1. 使用 JSTL 的 fmt 标签2. 在 bean 中注入 ResourceBundleMessageSource 的示例, 使用其对应的 getMessage 方法即可3. 配置 LocalResolver 和 LocaleChangeInterceptor--><br><br><a href="i18n">I18N PAGE</a><br><br><a href="testExceptionHandlerExceptionResolver?i=10">Test ExceptionHandlerExceptionResolver</a><br><br><a href="testResponseStatusExceptionResolver?i=10">Test ResponseStatusExceptionResolver</a><br><br><a href="testDefaultHandlerExceptionResolver">Test DefaultHandlerExceptionResolver</a><br><br><a href="testSimpleMappingExceptionResolver?i=2">Test SimpleMappingExceptionResolver</a></body></html>

⑥MyJsp.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <base href="<%=basePath%>">        <title>My JSP 'MyJsp.jsp' starting page</title>    <meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0">    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--><script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>  </head>    <body>   <script type="text/javascript">   $(function(){$("#testJson").click(function(){var url = this.href;var args = {};$.post(url, args, function(data){var id = data.id;var lastName = data.departmentName;alert(id + ": " + lastName);});return false;});})   </script>      <a href="testOut1">直接响应String字符串</a><br/>   <a href="testOut2" id="testJson">Json</a><br/>    <a href="testOut4" >xml数据格式</a><br/>    <a href="testOut3" >下载</a><br/>  </body></html>

 

8.拦截器写法

  ① 拦截器两个类(讲解)

package com.atguigu.springmvc.interceptors;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;public class FirstInterceptor implements HandlerInterceptor{/** * 该方法在目标方法之前被调用. * 若返回值为 true, 则继续调用后续的拦截器和目标方法.  * 若返回值为 false, 则不会再调用后续的拦截器和目标方法.  *  * 可以考虑做权限. 日志, 事务等.  */public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {System.out.println("[FirstInterceptor] preHandle");return true;}/** * 调用目标方法之后, 但渲染视图之前.  * 可以对请求域中的属性或视图做出修改.  */public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("[FirstInterceptor] postHandle");}/** * 渲染视图之后被调用. 释放资源 */public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("[FirstInterceptor] afterCompletion");}}

 

package com.atguigu.springmvc.interceptors;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;public class SecondInterceptor implements HandlerInterceptor{/** * 多个拦截器的执行顺序 * 1.preHandle 根据配置的前后顺序执行 * 2.postHandle、afterCompletion 根据配置的前后反序执行 */public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {System.out.println("[SecondInterceptor] preHandle");return false;}/** * 调用目标方法之后, 但渲染视图之前.  * 可以对请求域中的属性或视图做出修改.  */public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("[SecondInterceptor] postHandle");}/** * 渲染视图之后被调用. 释放资源 */public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("[SecondInterceptor] afterCompletion");}}


  ② SpringMvc.xml中配置

<mvc:interceptors><!-- 配置自定义的拦截器 --><bean class="com.atguigu.springmvc.interceptors.FirstInterceptor"></bean><!-- 配置拦截器(不)作用的路径 --><mvc:interceptor><mvc:mapping path="/emps"/><bean class="com.atguigu.springmvc.interceptors.SecondInterceptor"></bean></mvc:interceptor></mvc:interceptors>


 

9.源码、jar下载

下载jar

0 0