Spring MVC【二】基于注解和代码的配置

目录

一、Spring MVC注解配置

1. 组件与依赖注解

2. 请求映射与参数注解

2.1 @RequestMapping:请求映射注解

2.2 请求参数匹配注解:@RequestParam

2.3 路径变量注解:@PathVariable

2.4 矩阵变量注解:@MatrixVariable

3 @ModelAttribute模型属性注解

3.1 使用在控制器普通方法中(没被请求映射注解标注的方法)

3.2 使用在映射注解的方法中

3.3 使用在方法参数中

二、基于代码的配置

1.Java代码进行SpringMVC的容器配置

2.Java代码替代web.xml文件的入口配置

三、MVC注解汇总


一、Spring MVC注解配置

在Spring基础框架中,使用<context:annotation-config /><context:component-scan />开启组件注册或依赖自动装载等注解功能。在SpringMVC项目中,<context:component-scan />还会开启@RequestMapping、@GetMapping等映射注解功能(也就是会注册RequestMappingHandlerMapping和RequestMappingHandlerAdapter等请求映射和处理组件),但是<context:component-scan />不支持数据转换或验证等注解功能。

SpringMVC提供了<mvc:annotation-driven />标签用于全面开启MVC相关的注解功能,该配置会注册用于处理请求映射相关的组件参数转换注解。注册时组件类型包括:

  • RequestMappingHandlerMapping:请求映射处理器映射器
  • RequestMappingHandlerAdapter:请求映射处理器适配器
  • ExceptionHandlerExceptionResolver:处理异常信息的异常解析器

除此之外,<mvc:annotation-driven />配置还会加载一些数据转换支持的注解实现类,包括:

  • 支持使用了ConversionService的实例对表单参数进行类型转换;
  • 支持使用@NumberFormat。该注解的作用是对数据类型进行格式化。
  • 支持使用@Valid对JavaBean进行JSR-303验证。
  • 支持JSON数据类型转换注解@RequestBodyResponseBody

1. 组件与依赖注解

与Spring核心容器一致,配置<context:component-scan />就可以自动扫描和注册对应包下的组件和依赖注入的注解。SpringMVC项目中可以使用对应不同层级更为精准的组件注解,具体使用如下:

  • @Controller:控制器组件;
  • @Service:服务组件;
  • @Repository:DAO层组件;
  • @Component:通用组件,使用于不好归类的组件类,如一些用于配置文件对应的类;

依赖注入的注解和核心容器基本相同:

  • @Resource:依赖注入,Java标准,默认按名称装配;
  • @Autowired:依赖注入,Spring定义,默认按类型装配。

2. 请求映射与参数注解

请求映射注解可以使用在类和方法上,基本注解是@RequestMapping,根据不同请求类型有不同的子注解,类似@GetMapping、@PostMapping,特定请求注解只接受特定类型的HTTP方法,而@RequestMapping可以通用。参数注解包括请求参数@RequestParam和路径变量@PathVariable等。

2.1 @RequestMapping:请求映射注解

@RequestMapping可以使用在@Controller注解类的类和方法中,应用在类中作为请求路径的前缀,结合方法中的路径组成完整的请求路径。如下:

@Controller
@RequestMapping("/annoDemo")
//@RequestMapping(value="/annoDemo")
public class AnnoDemoController {

	@RequestMapping("/hello")
	public ModelAndView hello() {
		ModelAndView modelAndView = new ModelAndView();
                //设置视图名和模型数据
		modelAndView.setViewName("hello");
		modelAndView.addObject("myUser", new User(1, "User 1"));

		return modelAndView;
	}
}

进行如下配置,浏览器访问相应的url就会显示hello.jsp页面。

<context:component-scan base-package="com.mec.springmvc.controller" />	
<mvc:annotation-driven />	
    		
<!-- 视图解析器 -->		
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 视图前缀 -->
    <property name="prefix" value="/WEB-INF/"></property>
    <!-- 视图后缀 -->
    <property name="suffix" value=".jsp"></property>
</bean>

(1)不同请求类型的映射

@RequestMapping后面可以直接指定路径,也可以使用value属性来指定路径。@RequestMapping是一个通用类型的请求映射,可以对应不同类型的请求(Spring中使用RequestMethod枚举维护请求类型),包括GET、HEAD、POST、PUT、PATCH、DELETE、OPTIONS和TRACE。其中的method属性用于指定不同类型的请求。

SpringMVC还提供了不同类型的子注解可以直接使用,包括@GetMapping、@PostMapping、@PutMapping、@DeleteMapping和PatchMapping。在实际应用开发中,对应HTTP的Get和Post请求,使用@GetMapping和@PostMapping即可,有时为了简化配置或兼容同一个请求地址,不同类型的请求全部使用@RequestMapping来配置,需要区分时再配合method属性。

@RequestMapping的匹配地址也支持ant分格的通配符,匹配规则如下:

  • ?:匹配任意一个字符
  • *:匹配任意多个字符
  • **:匹配多层路径

(2)请求内容的类型配置

在请求映射注解中,可以通过consumesproduces属性指定请求和返回的媒体格式类型。

  • consumes:处理请求的提交内容类型(Content-Type),例如application/json、text/html。使用此属性可以缩小请求映射的范围。consumes也支持反向表达,比如!text/plain(表示除text/pain外的所有类型)
  • produces:返回的内容类型,以上两个属性除了设置MIME类型外,还可以通过charset设置字符集。
@RequestMapping(value = "/users", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")、
@ResponseBody // 返回Json格式数据注解
public List<User> addUser() {
    List<User> users = new ArrayList<User>();
    users.add(new User(1, "郭靖"));
    users.add(new User(1, "黄蓉"));

    return users;
}

要执行如上方法,需先引入如下三个jar包,否则会返回415错误

jackson-annotations、jackson-databind、jackson-core

访问浏览器即可得到数据如下:

(3)请求头限制

设置@RequestMapping等注解的headers属性,可以限定映射包含此请求头参数的请求,缩小方法的映射范围。

(4)请求参数限制

通过对请求参数的匹配来缩小映射的范围,比如某个映射地址通过URL传递一个名为name的参数,完整请求的URL是/request?name=value,在@RequestMapping中除了使用path属性匹配路径,还可以使用params匹配传递的参数。

@RequestMapping(path = "/request", params = "name=value")
public ModelAndView requestWithParams() {
    //……
    return null;
}

2.2 请求参数匹配注解:@RequestParam

@RequestParam使用在映射方法的形参中,用来匹配一些简单类型和没有被其他参数解析器解析的请求参数。默认情况下,请求参数与映射方法参数需要同名,而且该参数不能省略必须存在,否则会抛出异常,请求处理的方法也不会执行。不过可以通过设置required属性为false取消这个限制(一般参数非必须时才进行此项设置),还可以通过value属性设置映射到的前端请求的参数名。

@RequestMapping(path = "/helloWithParam")
public ModelAndView helloWithParam(@RequestParam(value = "userName", required = true) String userName) {
    System.out.println("userName: " + userName); // 获取到前端传来的参数值
    return null;
}

映射方法参数的@RequestParam也可以不使用,容器会根据参数名称自动进行匹配。如果参数是一个对象类型的话,容器会将请求中的参数自动装箱,也就是创建该类型的对象,并将前端传递的参数自动匹配到对象的属性中。

@RequestMapping(path = "/helloWithParam")
public ModelAndView helloWithParam(User user) {
    System.out.println("id : " + user.getId());
    System.out.println("name : " + user.getName());
    return null;
}

public class User {
    private int id;
    private String name;
}

这种需要注意前端传过来的参数名要和User类中的成员名一致,且数量要一致。

/helloWithParam?name=123&id=1    //得到结果
/helloWithParam?name=123&rr=1    //异常
/helloWithParam?name=123         //异常

2.3 路径变量注解:@PathVariable

@PathVariable注解使用在映射方法参数中,用来绑定映射注解中URL占位符的值并赋给该参数,占位符使用{}的格式,如下:

@RequestMapping("/helloPathVariable/{userName}")
public ModelAndView helloPathVariable(@PathVariable String userName) {
    // 浏览器请求:http://localhost:9090/SpringMVC/annoDemo/helloPathVariable/user1?name=yang
    System.out.println("userName: " + userName); // 输出user1
    return null;
}

2.4 矩阵变量注解:@MatrixVariable

在使用@PathVariable注解映射路径时,可以结合@MatrixVariable注解在请求URL路径中附加键值对方式的参数传递,路径和参数以分号(;)分隔,参数的键和值以等号(=)分隔。

@RequestMapping("/helloMatrixVariable/{userName}")
public ModelAndView helloMatrixVariable(@PathVariable String userName,
    @MatrixVariable(name = "id", pathVar = "userName") String userId) {
//浏览器访问:http://localhost:9090/SpringMVC/annoDemo/helloMatrixVariable/user1;id=12
    System.out.println("userName: " + userName); // 输出 user1
    System.out.println("userId : " + userId); // 输出 12
    return null;
}

注意使用该注解的前提时得先开启该注解功能,否则会报错。核心配置文件中配置如下

<mvc:annotation-driven enable-matrix-variables="true" />

@MatrixVariable注解的name属性指定参数的键的名字pathVar指定路径变量的名字,在包含多个路径变量时需要使用。如果参数的键和方法的@MatrixVariable注解的形参变量同名且只有一个路径变量时,可以省略name和pathVar属性的配置。

同一个路径地址,可以包含多个路径变量。在同一个路径变量中,可以包含多个键值对的参数,以分号(;)分割。@MartixVariable注解的方法参数可以得到所有的矩阵变量。键相同的会合并成集合。如果不同路径变量中都包含同一个键值,在不使用pathVar指定具体哪个路径变量的情况下,返回的键值是一个集合。

@RequestMapping("/depts/{deptId}/users/{userId}")
public ModelAndView helloMatrixVariable(@MatrixVariable MultiValueMap<String, String> matrixVars,
			@MatrixVariable(pathVar = "userId") MultiValueMap<String, String> userAtts) {
//浏览器访问  http://localhost:9090/SpringMVC/annoDemo/depts/dept001;att1=value1/users/user001;att1=value11;att2=value2

    // matrixVars匹配的值是{att1=[value1,value11], att2 = [value2]}
    // userAtts匹配的值是{att1=[value11], att2=[value2]}
    return null;
}

上面第一个参数的@MatrixVariable注解中没有使用pathVar属性只当具体哪个路径变量,所以合并了后面的att1。

3 @ModelAttribute模型属性注解

@ModelAttribute注解将数据添加到模型中,用于视图展示。该注解一般会使用在控制器中,控制器可以包含任意数量的@ModelAttribute注解方法,这些方法会在同一控制器中的@RequestMapping注解方法之前被调用。@ModelAttribute方法也可以通过@ControllerAdvice在控制器之间共享。它可以使用在控制器的普通方法、方法参数或注解了@RequestMapping的请求映射处理方法中,在不同场景下所使用的含义也不相同。

3.1 使用在控制器普通方法中(没被请求映射注解标注的方法)

@ModelAttribute注解的方法会在每个映射请求方法之前执行,可以使用@RequestParam获取请求参数,通过Model类型的参数设置模型的属性值。

@Controller
public class ModelAttributeAnnoController { // 控制器类
	@ModelAttribute // 设置模型数据
	public void modelAttrMethod1(@RequestParam String name, Model model) {
		model.addAttribute("name", name);
	}

	@ModelAttribute // 设置模型数据
	public void modelAttrMethod2(@RequestParam String id, Model model) {
		model.addAttribute("id", id);
	}

	@RequestMapping("/modelAttrInMethod")
	public String modelAttrInMethod() {
		return "modelattribute"; // 返回一个字符串,代表视图名
	}
}

浏览器访问

http://localhost:9090/SpringMVC/modelAttrInMethod?id=123&name=yang

上述示例获取参数值后两个方法分别设置了name和id的模型属性值。这些属性值在请求映射返回的视图最终对应modelattribute.jsp文件中,使用${name}和${id}获取。Jsp页面展示如下:

以上@ModelAttribute注解的方法包含了一个Model类型的参数,方法的返回值类型是void。返回值也可以是一个具体类型的对象,框架会将返回对象的类名首字母小写作为键加入模型对象中(这个事情是框架来做的)。比如如果返回基本类型,那么对应的键可能是int、string、float等。当然更多的是自定义类,加入将获取的有需要的参数都封装在自定义对象中,那么还注解的方法中就可以不用Model类型的参数了。模型对象中的键名也可以显式指定,如:@MatrixAttribute("attributeName")。

3.2 使用在映射注解的方法中

@ModelAttribute和@RequestMapping可以同时注解同一个方法,如果该方法返回的是一个字符串类型,这个字符串代表的就不是视图名,而是模型的属性值

@RequestMapping("/modelAttrInMethod")
@ModelAttribute("modelAttrKey")    //这里如果不指定键,那么键的值则为string
public String modelAttrInMethod() {
    return "modelAttrValue";
}

如上返回值会作为模型的属性值。而返回的视图名称则通过转换映射的请求地址的来,也就是说会去找/modelAttrInMethod路径对应的同名的JSP文件modelAttrInMethod.jsp

3.3 使用在方法参数中

在方法参数前使用@ModelAttribute注解,则会从隐含的模型对象中获取键是参数名的属性值并将这个值赋给注解的参数

@Controller
public class ModelAttributeAnnoController { 

	@ModelAttribute
	public User modelAttrMethod1(@RequestParam String id, @RequestParam String name) {
		return new User(Integer.parseInt(id), name);
	}

	@ModelAttribute // 这里添加该注解是标注方法,以便框架调用
	public void modelAttrMethod2(@ModelAttribute User user) {    //标注在方法的形参中
		System.out.println("id : " + user.getId());
		System.out.println("name : " + user.getName());
	}

	@RequestMapping("/modelAttrInMethod")
	public String modelAttrInMethod() {
		return "modelattribute";
	}
}

上述modelAttrMethod1将请求的参数值封装在user对象中,隐含的Model类型对象会以{“user”:user}设置属性,然后modelAttrMethod2中将该注解在参数上,参数user对应的user对象就是modelAttrMethod1中设置的这个user对象。

二、基于代码的配置

在传统的SpringMVC项目中,基本使用XML作为配置方式,包括使用XML文件配置Spring容器、使用web.xml文件作为项目的入口配置文件。也可以通过@Configuration注解类来进行容器的配置,自定义实现WebApplicationInitializer接口类来替代web.xml的配置,从而实现在项目中零XML配置。

1.Java代码进行SpringMVC的容器配置

在Spring核心容器中使用@Configuration的注解类来替代XML进行容器相关的配置,使用AnnotationConfigApplicationContext根据容器配置类进行应用上下文(ApplicationContext)的初始化。与核心容器类似,MVC容器也可以使用类似的方式进行Web应用上下文的配置和初始化。

SpringMVC提供了Web的应用上下文接口WebApplicationContext,该接口继承自ApplicationContext,除了管理Bean外,还提供了Web相关的一些特性,包括维护ServletContext对象和处理不同请求范围的Bean(request、session、application)。对应XML和代码注解配置方式,分别提供了XmlWebApplicationContext和AnnotationConfigWebApplicationContext的Web应用上下文实现类。

2.Java代码替代web.xml文件的入口配置

早期的Java Web项目必须要有一个web.xml的入口配置文件,Servlet才能被Tomcat等服务器识别、运行并在浏览器中访问。在Servlet3.0标准中提供了一个新的接口ServletContainerInitializer,允许在容器启动阶段通过代码进行Servlet、Filter和Listener等注册以及初始化参数配置等工作。Tomcat从7版本开始支持Servlet3.0。

public interface ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException; 
}

 在上述方法中可进行Servlet等初始化工作,这种方式使用的是Java SPI的实现机制,开发步骤包括:

  1. 定义一个ServletContainerInitializer接口的实现类;
  2. 在该实现类上标注注解@HandlesTypes(XX.class),括号里的类名是一个自定义的接口,该接口的子类可以用来进行Servlet配置等工作。onStartup方法的第一个参数就是这些该接口的所有实现类的集合;
  3. 在项目的META-INF/services/javax.servlet.ServletContainerInitializer文件中加上实现类的全路径名。(服务器在启动时,会扫描应用或jar包中的META-INF/services/javax.servlet.ServletContainerInitializer文件中配置的实现类,启动对应的onStartup()方法完成Servlet注册和加载等工作)

SpringMVC就是使用Servlet3.0机制实现web.xml的替代,在spring-web-XX.jar文件中定义了接口ServletContainerInitializer的实现类SpringServletContainerInitializer,该类的定义如下:

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
	@Override
	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		//省略调用WebAppInitializer的onStartup方法
	}

}

public interface WebApplicationInitializer {
    void onStartup(ServletContext servletContext) throws ServletException;
}

WebApplicationInitializer是Spring提供用于取代web.xml相关配置的接口,我们可以自定义该接口的实现类,在onStartup方法中完成Servlet等的初始化工作。

public class MyWebApplicationInitializer implements WebApplicationInitializer {

	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
//基于XML文件的Spring Web配置方式	
		/*
		 * XmlWebApplicationContext xmlWebContext = new XmlWebApplicationContext();
		 * xmlWebContext.registerShutdownHook();
		 * xmlWebContext.setConfigLocation("classpath:springmvc.xml");
		 */
//基于代码的Spring Web配置方式		
		AnnotationConfigWebApplicationContext annoWebContext = new AnnotationConfigWebApplicationContext();
		annoWebContext.register(WebAppConfig.class);
		annoWebContext.registerShutdownHook();
		annoWebContext.refresh();

		// 初始化中央控制器
		DispatcherServlet servlet = new DispatcherServlet(annoWebContext);
		// 注册中央控制器
		ServletRegistration.Dynamic regsitration = servletContext.addServlet("dispatcher", servlet);
		regsitration.setLoadOnStartup(1); // 设置servlet容器启动时加载该Servlet
		regsitration.addMapping("/"); // 设置路径拦截映射
	}

}

如上,若采用代码方式完成Spring Web核心配置的话将XML文件中的配置搬过来即可,如下:

@Configuration
@ComponentScan(basePackages = { "com.mec.springmvc.controller" })
public class WebAppConfig {
    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        return new InternalResourceViewResolver("/WEB-INF/", ".jsp"); // 两个参数分别是视图前缀和视图后缀
    }
}

三、MVC注解汇总

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值