《Spring实战》学习笔记-------MVC

1. MVC请求流程

在这里插入图片描述

  1. 请求携带着URL和提交的其它信息被DispatcherServlet拦截
  2. DispatcherServlet查询处理器映射决定下一站要给哪个控制器
  3. DispatcherServlet将请求发送给选择的控制器,将数据提交给它并等待处理
  4. 控制器完成处理后会返回一些信息(model),这些信息需要一个视图(view)来显示,所以它选定一个视图名(只是一个视图名,不代表视图本身),将它们一起发回DispatcherServlet
  5. DispatcherServlet使用视图解析器(view resolver)将视图名匹配为一个特定的视图实现(这里是视图主体)
  6. DispatcherServlet交付数据模型(model)给特定的视图
  7. 视图渲染好数据再返回给客户端

2. 搭建SpringMVC

配置DispatcherServlet

package spittr.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected String[] getServletMappings() {
		return new String[] {"/"};
	}
	
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class<?>[] {RootConfig.class};
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class<?>[] {WebConfig.class};
	}
}
  • getServletMappings()方法,将一个或多个路径映射到DispatcherServlet。“/”代表它会处理应用的所有请求
  • getServletConfigClasses()和getRootConfigClasses():
    Spring中可以创建出多个DispatcherSerlet(只要有多个继承AbstractAnnotationConfigDispatcherServletInitializer的类就好了)。每个DispatcherServlet都有自己的上下文(WebApplicationContext),且配置只对它自己有效,这也就是getServletConfigClasses()方法所获取的它自己的配置类。例如Controller,ViewResolver,HandlerMapping等会在WebConfig中配置。
    除了每个DispatcherServlet配置类的上下文,还有一个根应用上下文,这个RootConfig的作用是在多个DispatcherServlet之间共享Bean,这就是getRootConfigClasses()的作用。例如数据源等公共的bean会在RootConfig中配置。
  • DispatcherServlet获取想要的bean时,如果没有在自己的应用上下文中找到,则会自动到根应用上下文中去找。

WebConfig类:

package spittr.config;

@Configuration
@EnableWebMvc
@ComponentScan("spittr.web")
public class WebConfig implements WebMvcConfigurer{

	@Bean
	public ViewResolver viewResolver() {
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setPrefix("/WEB-INF/views/");
		resolver.setSuffix(".jsp");
		resolver.setExposeContextBeansAsAttributes(true);
		return resolver;
	}
	
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
}
  • @EnableWebMvc :启用SpringMVC
  • @ComponentScan :启用组件扫描(扫描spitter.web中的带@Controller注解的控制器),如果不启用,Spring只拿找到显式配置类中的控制器
  • viewResolver : 配置JSP视图解析器
  • configureDefaultServletHandling :配置静态资源的处理,否则DispatcherServlet会处理所有的请求即使并不需要处理信息。

RootConfig类:

package spittr.config;

@Configuration
@ComponentScan(basePackages= {"spittr"}, 
				excludeFilters= {@Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)})
public class RootConfig {

}

3. 编写控制器

处理对“/”的请求的控制器,展现首页:

package spittr.web;

@Controller
public class HomeController {

	@RequestMapping(value="/", method=RequestMethod.GET)
	public String home() {
		return "home";
	}
}

@Controller注解和@Component注解效果一样,目的是辅助实现组件扫描。

测试类:

package BaseTest;

public class HomeControllerTest {
	
	@Test
	public void testHomePage() throws Exception{
		HomeController controller = new HomeController();
		MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
		mockMvc.perform(MockMvcRequestBuilders.get("/")).andExpect(MockMvcResultMatchers.view().name("home"));
	}
}

4. 接收请求参数

接收请求参数除了URL传参还可以通过路径来传参:

@RequestMapping("/{spittleId}") //这里上一级的RequestMapping注解的路径是/Spittle
	public ModelAndView spittleid(ModelAndView modelAndView,  @PathVariable("spittleId") long spittleId) {
		System.out.println(spittleId);
		modelAndView.addObject(repository.findSpittle(12345, 1));
		modelAndView.setViewName("Spittle");
		return modelAndView;
	}

通过使用{}占位符和@PathVariable注解,路径是“*/Spittle/12345” 就可以将12345接收为“spittleId”。


5. 对表单校验(使用Java校验API检查bean的属性是否合法)

Java校验API提供多个放在Bean属性上的注解来限制属性的值,达到校验的作用:

  • @AssertFalse : 元素必须是布尔值,且为false
  • @AssertTrue
  • @DecimalMax:元素必须数字,且它要小于等于给定的BigDecimalString值
  • @DecimalMin:大于等于
  • @Digits:元素必须是数字,且要有指定的位数
  • @Future:元素的值必须是一个将来的日期
  • @Past:过去的日期
  • @Max:元素必须数字,且它要小于等于给定的值
  • @Min:大于等于
  • @NotNull:元素不能为空
  • @Null
  • @Patten:元素值必须匹配给定的正则表达式
  • @Size:元素值必须是String、集合、数组,并且长度要符合给定的限制

以上注解是添加在Bean属性上的,在Controller中要配合@Valid注解和Errors类使用

@RequestMapping("xxx")
public String validBean(@Valid Bean bean, Errors errors){
	if(errors.hasErrors()){
		return "错误页面";
	}
	return "成功页面";
}

6. SpringMVC的其它配置

6.1 自定义DispatcherServlet配置****

除了之前必须要重载的三个方法,还可以进行额外的配置,可以借助customizeRegistration()方法通过参数Dynamic进行额外的配置

在配置DispatcherServlet类中(前文的配置类是SpittrWebAppInitializer)加上:

	@Override
	protected void customizeRegistration(Dynamic registration) {
		registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
	}

这个样例设置了对multipart(例如处理上传图片的二进制数据)的支持,设置了上传文件的临时存储目录。


6.2 添加其它的Servlet和Filter

使用Java方式想在Web容器中注册其它组件的话,只需要创建一个新的初始化器(实现WebApplicationInitializer接口)。可以定义任意数量的初始化器:

注册Servlet:

public class MyServletInitializer implements WebApplicationInitializer {

	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		// TODO Auto-generated method stub
		Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class);
										//注册Filter这里就使用addFilter方法
		myServlet.addMapping("/custom/*");
										//filter.addMappingForUrlPatterns(null, false, "/custom/*")
	}
}

6.3 Web.xml中声明DispatcherServlet

<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name> <!-- 设置根上下文配置文件位置 -->
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<listener>
		<listener-class>                               <!-- 注册ContextLoaderListener -->
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	
	<servlet>
		<servlet-name>addServlet</servlet-name>        <!-- 注册DispatcherServlet-->
		<servlet-class>
			org.springframework.web.context.DispatcherServlet
		<servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>addServlet</servlet-name>        <!-- 将DispatcherServlet映射到“/”-->
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

6.4 处理异常

  • 添加@ResourceStatus注解,将异常映射为HTTP状态码

例如:新定义一个异常,并将它映射为404

@ResourceStatus(value=HTTPStatus.NOT_FOUND, reason="Spittle Not Found")
public class NewException extends RuntimeException{
}
  • 还可以在方法上添加@ExceptionHandler注解来处理抛出的异常
@ExceptionHandler(NewException.class)
public String handleNewException(){
	return "error";
}

这个注解只能处理同一个Controller中的NewException异常


6.5 为控制器添加通知(通常是异常处理通知)*

控制器通知是任意带有@ControllerAdvice注解的类。

它最常用的场景是将所有@ExceptionHandler方法收集到一个类中。
例如:实现在所有控制器抛出NewException时都能进行统一处理:

@ControllerAdvice
public class AppWideExeptionHandler{
	
	@ExceptionHandler(NewException.class)
	public String handleNewException(){
		return "error";
	}
}

7. 重定向请求携带数据

7.1 URL模板重定向

如果是简单的值,例如name,id之类,可以通过URL来传递路径变量和参数。

@RequestMapping(value="/regitster", method=GET)
public String xxxx(Username username, Model model){
	model.addAttribute("username", username);
	return "redirect:/other/{username}";
	//如果传参数,比如再传递id,只需要model.addAttribute("userId",id),返回的URL会自动变成 /other/username?userId=111  ,
}

// 配合@RequestMapping("/other/{username}")控制器使用

返回“redirect:/路径”可以实现重定向(再发一次HTTP请求),“forward:/路径”可以实现请求转发。

在URL传参时要使用{}占位符,可以对不安全的字符进行转义,更加安全。


7.2 使用flash属性

Spring提供了将数据发送为flash属性的功能,flash属性会一直携带这些属性直到下一次请求,然后才消失。

Spring提供了RedirectAttributes类来设置flash属性,它是Model的一个子接口。

//这次我们传送一个User对象作为参数
@RequestMapping(value="/regitster", method=POST)
public String xxxx(User user, RedirectAttributes model){
	model.addAttribute("username", username);
	model.addFlashAttribute("user", user); //这个key默认名是value的类型,User就是"user"
	return "redirect:/other/{username}";
}

// 配合@RequestMapping("/other/{username}")控制器使用

在重定向前,flash属性会赋值到会话中,重定向完成后,再从会话转移到模型中。属性可以直接在视图页面中拿到,也可以在下一个控制器通过model.getFlashAttributes取出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值