Spring实战——Spring MVC的高级技术

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fancheng614/article/details/85311175

先回顾一下Spring实战——构建Spring Web应用程序中使用java配置构建的SpringMVC框架。以下会提供SpringMVC配置的替代方案。

一、SpringMVC配置的替代方案

注意:在Spring实战——构建Spring Web应用程序一文中说过:使用java配置SpringMVC时只支持Servlet3.0的容器,据我所知,目前在企业里大部分还是使用的xml进行配置。

1、使用纯xml配置SpringMVC

web.xml配置内容:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  	<!-- 设置根上下文配置文件位置-->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<!-- 注册ContextLoaderListener -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
  
    <!-- 注册DispatcherServlet -->
	<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:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<!-- 将DispatcherServlet映射到"/"-->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

applicationContext.xml

	<context:annotation-config></context:annotation-config>
	<context:component-scan base-package="com.mfc"></context:component-scan>

spring-mvc.xml

	<context:annotation-config></context:annotation-config>
	<context:component-scan base-package="com.mfc.ctrl"></context:component-scan>
	
	<mvc:annotation-driven></mvc:annotation-driven>
	<mvc:default-servlet-handler/>
	
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

完成以上配置即可实现SpringMVC的测试了。

二、处理multipart形式的数据(就是文件上传)

参考以前的博客:springMVC上传图片

三、处理异常

1、Spring提供了多种方式将异常转换为响应

      ①特定的Spring异常将会自动映射为指定的HTTP状态码

      ②异常上可以添加@responseStatus注解,从而将其映射为某一个指定的HTTP状态码

      ③在方法上面添加@ExceptionHandler注解,使其处理异常

2、Spring的一些异常会默认映射为HTTP状态码

Spring异常 HTTP状态码
BindException 400 - Bad Request
ConversionNotSupportedException 500 - Internal Server Error
HttpMediaTypeNotAcceptableException 406 - Not Acceptable
HttpMediaTypeNotSupportedException 415 - Unsupported Media Type
HttpMessageNotReadableException 400 - Bad Request
HttpMessageNotWritableException 500 - Internal Server Error
HttpRequestMethodNotSupportedException 405 - Method Not Allowed
MethodArgumentNotValidException 400 - Bad Request
MissingServletRequestParameterException 400 - Bad Request
MissingServletRequestPartException 400 - Bad Request
NoSuchRequestHandlingMethodException 404 - Not Found
TypeMismatchException 400 - Bad Request
   

3、处理异常的方式:

①可以在Controller的业务方法中处理,再Catch代码块中返回到指定的错误页面,如下:

	@RequestMapping("/testPage")
	public String testPage(@Valid TUser tUser, 
			@RequestParam("file")MultipartFile file,
			HttpServletRequest request,
			Model model){
		String path = request.getSession().getServletContext().getRealPath("upload");
		String name = file.getOriginalFilename();
		File targetFile = new File(path, name);
		try {
			file.transferTo(targetFile);
			System.out.println("upload/"+name);
		} catch (IllegalStateException e) {
			e.printStackTrace();
			return "errorPage";
		} catch (IOException e) {
			e.printStackTrace();
			return "errorPage";
		}
		model.addAttribute("path", "/upload/"+name);
		return "testPage";
	}

②以上方法每个Controller中捕获异常都需要return一次错误页面,会比较麻烦,可以使用@ExceptionHandler注解,在Controller中写一个专门处理处理异常的方法,这样一来这个处理异常的方法就可以处理同一个控制器中所有处理器方法抛出的异常,如下(下面这段代码可以加在每一个Controller的方法中):

	/**
	 * 本方法可以处理本控制器中所有的异常
	 * @return
	 */
	@ExceptionHandler(Exception.class)
	public String errorPage(){
		return "errorPage";
	}

③在②中的方法虽然统一处理了当前Controller中的所有异常,但是如果在每一个Controller类中都添加一个处理异常的方法难免比较麻烦,这时我们可以将这个处理异常的方法写在所有Controller都要继承的父类里面,此时这一个方法就可以处理所有Controller的异常了。还有一个更简单的方法就是为控制器添加通知,使用@ControllerAdvice注解,如下(下面这个类可以处理所有Controller中的异常了):

/**
 * @author 74790
 * 异常通知控制器
 */
@ControllerAdvice
public class ExceptionCtrl {
	@ExceptionHandler(Exception.class)
	public String errorPage(){
		return "errorPage";
	}
}

四、跨重定向请求传递数据

1、当一个请求在Controller的方法内走完逻辑程序时,需要重定向到另一个Controller的方法,此时就需要用到重定向了,也就是redirect。问题来了,当前一个Controller重定向时,原始的请求就结束了,就会发起一个新的GET请求,此时在发起重定向的方法怎么发送数据给重定向的目标方法呢?两种方法:

     ①使用URL模板以路径变量和 / 或查询参数的形式传递数据

     ②通过flash属性发送数据

2、通过URL传递数据:

下面两个方法中,testPage会向testRedirect重定向,并会带着参数name和path传过去。

	@RequestMapping("/testPage")
	public String testPage(@Valid TUser tUser, 
			@RequestParam("file")MultipartFile file,
			HttpServletRequest request,
			Model model){
		String path = request.getSession().getServletContext().getRealPath("upload");
		String name = file.getOriginalFilename();
		File targetFile = new File(path, name);
		try {
			file.transferTo(targetFile);
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		model.addAttribute("path", "/upload/"+name);
		model.addAttribute("name", name);
		return "redirect:../testCtrl/testRedirect/{name}";
	}
	
	@RequestMapping("testRedirect/{name}")
	public String testRedirect(Model model,@PathVariable("name")String name,
			@RequestParam("path")String path){
		System.out.println(name);
		System.out.println(path);
		model.addAttribute("path", path);
		return "testPage";
	}
	

3、在2中的方法重定向时通过URL带过去了两个参数name和path,但是这种方法始终只能传递一些简答的数据。如果在testPage查出了一个对象,而在testRedirect中需要使用这个对象,这时就需要把整个对象传递过去(当然,你也可以传递查询到这个对象的条件,然后再testRedirect中再查询一遍,但是这样似乎不太好),此时需要用flash,但是这里注意,在需要重定向的方法中已经不是使用的Model了,而是使用的RedirectAttributes,RedirectAttributes提供了Model的所有功能。代码如下:

	@RequestMapping("/testPage")
	public String testPage(@Valid TUser tUser, 
			@RequestParam("file")MultipartFile file,
			HttpServletRequest request,
			RedirectAttributes model){
		String path = request.getSession().getServletContext().getRealPath("upload");
		String name = file.getOriginalFilename();
		File targetFile = new File(path, name);
		try {
			file.transferTo(targetFile);
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		model.addAttribute("path", "/upload/"+name);
		model.addAttribute("name", name);
		model.addFlashAttribute("tUser", tUser);
		return "redirect:../testCtrl/testRedirect/{name}";
	}
	
	@RequestMapping("testRedirect/{name}")
	public String testRedirect(Model model,@PathVariable("name")String name,
			@RequestParam("path")String path){
		//本方法中TUser对象已经直接存在了flash中,在testPage对应的页面上使用EL表达式 ${tUser.userName} 就可以获取到userName
		System.out.println(name);
		System.out.println(path);
		//判断flash中是否有tUser这个对象
		boolean flag = model.containsAttribute("tUser");
		System.out.println(flag);
		model.addAttribute("path", path);
		return "testPage";
	}
	

猜你喜欢

转载自blog.csdn.net/fancheng614/article/details/85311175