一、设置扫描包中的注解
1、设置扫描包中的注解,完成对象创建及属性注入。
<context:component-scan base-package="com.zqwl.service,com.zqwl.mapper">
注意事项:@Component注解及子注解使用时,如果没有明确指定bean的名称,默认名称为类名首字母变小写。
二、常用注解
1.@Autowired自动注入的注意事项
(1)底层使用反射直接操作属性完成属性值的自动注入。
@Service
public class UserServiceImpl {
@Autowired
UserMapperImpl userMapper;
}
(2)底层使用set方法完成属性值的自动注入。
@Service
public class UserServiceImpl {
UserMapperImpl userMapper;
@Autowired
public void setUserMapper(UserMapperImpl userMapper) {
this.userMapper = userMapper;
}
}
(3)底层使用构造方法完成属性值的自动注入。
@Service
public class UserServiceImpl {
UserMapperImpl userMapper;
public UserServiceImpl() {
}
@Autowired
public UserServiceImpl(UserMapperImpl userMapper) {
this.userMapper = userMapper;
}
}
2.Spring Test 模块整合Junit单元测试工具
整合后可以在测试类中直接使用Spring容器中的内容,把测试类也放入到Spring容器中,测试类里面可以直接使用注解注入容器中的bean对象。同时也可以通过@ContextConfigration注解指定配置文件路径,让测试方法在启动的时候直接加载配置文件。
// 使用Spring整合Junit4的类启动当前测试类
@RunWith(SpringJUnit4ClassRunner.class)
// 启动时加载的配置文件,里面要包含classpath
@ContextConfiguration(locations = "classpath:applicatonContext.xml")
public class MyTest {
@Autowired
PeopleService peopleService;
@Test
public void test2(){
peopleService.test();
}
}
3.@Component注解
作用:相当于配置文件的bean标签,将某个类的对象扫描到Spring容器中。此注解一般在普通Java类上用。
注意事项:默认类名的首字母小写即为bean对象的ID,也可以使用注解的value属性声明自定义的ID,value可以省略不写。
使用方式:声明在类上。
@Component("advice")
public class MyAdvice {
}
4.@Aspect注解
作用:声明该类为通知类。
使用方式:结合@Component在通知类上使用,Spring扫描到容器中并作为通知类。
@Component("advice")
@Aspect
public class MyAdvice {
}
5.@Service注解
作用:相当于配置文件的bean标签,将某个类的对象扫描到Spring容器中。此注解专门在业务层实体类上使用来表明该类为业务类。
注意:默认类名的首字母小写即为bean对象的ID,也可以使用注解的value属性声明自定义的ID,value可以省略不写。
@Service("us")
public class UserServiceImpl implements UserService {
......
}
6.@pointcut注解
作用:声明切点。
使用方式:方法上使用。
@Component("advice")
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.zqwl.service.*.*(..))")
public void pointcut(){}
}
7.@Before注解
作用:声明方法为前置通知方法。
使用方式:在前置通知方法上声明。
注意:需要在其中声明对应的切点的路径,非同包中需要指定全限定路径。
@Component("advice")
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.bjsxt.service.*.*(..))")
public void p(){}
//前置通知
@Before("p()")
public void before(){
System.out.println("我是前置通知");
}
}
8.@After注解
作用:声明方法为后置通知方法。
使用方式:在后置通知方法上声明。
注意:需要在其中声明对应的切点的路径,非同包中需要指定全限定路径。
//后置通知
@AfterReturning("p()")
public void after(){
System.out.println("我是后置通知");
}
9.@Around注解
作用:声明方法为环绕通知方法。
使用方式:在环绕通知方法上声明。
注意:需要在其中声明对应的切点的路径,非同包中需要指定全限定路径。
@Around("p()")
public Object round(ProceedingJoinPoint pp) throws Throwable {
System.out.println("环绕-前");
Object proceed = pp.proceed();
System.out.println("环绕-后");
return proceed;
}
10.@AfterThrowing注解
作用:声明方法为异常通知方法。
使用方式:在异常通知方法上声明。
注意:需要在其中声明对应的切点的路径,非同包中需要指定全限定路径。
@AfterThrowing(value = "p()",throwing = "e")
public void myThrow(Exception e){
System.out.println("我是异常通知");
}
11.注解配置声明式事务
Spring 注解配置事务时,只需要在需要有事务管理的方法上添加@Transactional注解。必须保证配置注解的方法所在的类已经放入到Spring容器中。
配置注解扫描
<context:component-scan base-package="com.zqwl.service.impl"></context:component-scan>
开启事务注解的支持
<tx:annotation-driven></tx:annotation-driven>
必须配置事务管理器类
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
使用注解配置事务重要提示:
@TransactionManager 默认寻找叫做transactionManager的事务管理器。如果没有找到会报异常NoSuchBeanDefinitionException。所以,如果希望配置注解时简单点直接写@Transactional就生效,就必须在XML配置事务管理器时,id必须叫做transactionManager。
如果在XML配置事务管理器时,id不叫transactionManager,需要在@Transactional(transactionManager="XML配置时id值")。
@Transactional用在类上,整个类中方法都生效。
@Transactional用在方法上,该方法生效。用在方法上优先级更高。
12.声明式事务四个基础属性
11.1 name属性
配置哪些方法需要有事务控制,支持*通配符。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 表示所有以insert开头的方法需要进行事务管理 -->
<tx:method name="insert*"></tx:method>
<!-- 表示所有方法需要进行事务管理-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
11.2 readonly属性(true|false)
是否为只读事务。
true:告诉数据库此事务为只读事务。底层支持查询的代码逻辑,不走提交事务和回滚事务的代码,会对性能有一定提升,所以只要是查询的方法,建议设置readonly="true"。
false(默认值):需要控制的事务。新增,删除,修改,不设置readonly属性或设置readonly="false"。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 所有select开头的方法执行查询逻辑 -->
<!-- 多个tx:method标签时取交集-->
<tx:method name="select*" read-only="true"></tx:method>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
11.3 rollback-for属性
异常类型全限定路径,表示出现什么类型的异常进行数据回滚。
默认运行时异常及子类异常回滚,检查时异常不回滚。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 定义只要方法出现了Exception类型异常及子类型异常都需要进行回滚 -->
<tx:method name="insert*" rollback-for="java.lang.Exception"></tx:method>
<tx:method name="select*" read-only="true"></tx:method>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
11.4 no-rollback-for属性
异常类型全限定路径,当出现什么异常的时候不进行数据回滚。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 定义只要出现运行时异常就不回滚 -->
<tx:method name="insert*" no-rollback-for="java.lang.RuntimeException"></tx:method>
<tx:method name="select*" read-only="true"></tx:method>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
13.@RequestMapping注解
@RequestMapping注解可以写在控制器类上,也可以写在控制单元方法上。
13.1 value属性
value:定义映射路径。URL中出现指定映射路径时会执行当前控制单元。支持一个方法多个映射路径。value属性名可以省略不写,且Java的注解中,如果属性是数组类型,且取值只有一个时,{}可以省略不写。所以一共有四种写法。
但是需要注意:如果@RequestMapping只需要设置value属性的话value可以省略。但是需要设置多个属性时value不能省略。
取值前面的/
表示映射到项目根目录,可以省略不写,但是从规范上建议写上。
13.2 name属性
name:给控制单元定义一个名称。可以理解name是控制单元的注释。
@RequestMapping(value = "/testName",name = "测试下name属性")
public String testName(){
return "first.jsp";
}
13.3 path属性
path属性和value属性使用方式是相同的,都是设置控制单元的映射路径。5
@RequestMapping(path = "/testPath")
public String testPath(){
return "first.jsp";
}
13.4 method属性
当设置了method属性后,表示只有指定类型请求方式才能访问这个控制单元方法,其他的请求方式访问时,响应会出现405状态码。
// 请求方式只能是DELETE和POST类型。
@RequestMapping(value = "/testMethod",method = {RequestMethod.DELETE,RequestMethod.POST})
public String testMethod(){
return "first.jsp";
}
13.5 params属性
params属性类型是String[],表示请求中必须包含指定名称的请求参数。
@RequestMapping(value="/testParam",params = {"name"})
public String testParam(){
return "first.jsp";
}
如果请求中没有包含指定类型参数,响应会出现400状态码。并且明确提示在实际的请求参数中没有明确设置name属性。
13.6 headers属性
headers属性类型是String[],表示请求头中必须包含指定的请求头参数。
@RequestMapping(value="/testHeaders",headers = "Bjsxt")
public String testHeaders(){
return "first.jsp";
}
13.7 consumes属性
consumers表示处理请求内容(Content-Type)的类型,平时多不设置,由Spring MVC自动判断。
13.8 produces属性
produces类型是String[],作用是设置@ResponseBody注解的响应内容类型。且仅当请求头中Accept中包含的值才生效。
@RequestMapping(value="/testProduces",produces = "text/html;charset=utf-8")
@ResponseBody
public String testProduces() throws IOException {
return "这是中文";
}
14. @ResponseBody注解
@ResponseBody注解是类或方法级注解。当方法上添加@ResponseBody注解后,控制单元方法返回值将不再被视图解析器进行解析 | 不会使用转发。而是把返回值放入到响应流中进行响应。
@RestController注解
像这种类中所有的控制单元方法都有@ResponseBody,可以使用@RestController进行简化。当类上使用的是@RestController而不是@Controller时,控制单元方法不再需要写@ResponseBody(也不能写@ResponseBody),Spring MVC在解析控制单元方法时会自动带有@ResponseBody注解。
所以:@RestController写起来更加简单了。
但是需要注意:一旦类上使用了@RestController,所有控制单元返回都是XML或JSON数据。而无法实现页面跳转功能了。
所以:只要类中有一个方法是希望实现页面跳转功能,类上就不能使用@RestController。只有类中所有的方法都是返回JSON或XML的情况才能使用@RestController注解。
15、@RequestBody注解
@RequestBody注解底层依赖的依然是Jackson工具包,其作用是把客户端传递过来的请求体中JSON或XML数据转换为Map、类、List<类>、List<Map>等类型。既然是转换为请求体数据,所以不能是GET类型请求(GET没有请求体),多用在POST类型的请求中。@RequestBody注解在单体架构项目使用的不是特别多。主要用在分布式项目中多个项目之间传递数据或一些开发平台中(例如微信开发平台接口返回XML数据)如果希望在单体架构项目中使用@RequestBody注解,需要在客户端中使用Ajax请求,刻意设置请求的内容类型(Content-Type)为JSON或XML。
三、Spring MVC异常处理
1. 局部配置
配置在@Controller的控制器类中,只有当前这个控制器类的控制单元出现异常时才能执行,其他类的控制单元出现异常不能执行。
每个控制器类中可以有多个处理异常的方法。每个方法上面只需要有@ExceptionHandler,千万别添加了@RequestMapping注解。
@Controller
public class DemoController {
@RequestMapping("/demo")
@ResponseBody
public String demo2(){
Object obj = null;
obj.toString();
return "demo2";
}
@ExceptionHandler(value = ArithmeticException.class)
public String myexception(){
System.out.println("Demo-1");
return "forward:/exception.jsp";
}
@ExceptionHandler(value = Exception.class)
public String myexception2(){
System.out.println("Demo-2");
return "forward:/exception2.jsp";
}
}
2. 全局配置
因为@ControllerAdvice已经继承了@Component注解,所以类上只添加这个注解就可以了。
不需要在添加@Controller注解了。
小提示:
如果配置了局部异常处理器和全局异常处理器,优先匹配局部异常处理器。
@ControllerAdvice
public class MyExceptionController {
@ExceptionHandler(value = ArithmeticException.class)
public String myexception(){
System.out.println("MyException-1");
return "forward:/exception.jsp";
}
@ExceptionHandler(value = Exception.class)
public String myexception2(){
System.out.println("MyException-2");
return "forward:/exception2.jsp";
}
}
四、Spring MVC数据校验
1.Hibernate Validator
里面所有注解都包含message属性,表示校验不通过后日志打印的信息。
2.在实体类属性上添加注解
示例中只是以NotNull和Length进行举例。
(1)@NotNull中message是可选属性,如果设置了message,在违反规则后日志会打印message中内容。
(2)@Length是设置字符串长度。
所以name必须不能是null的,且长度是2-6位。
注解放在实体类的属性上面,每个实体类属性都支持配置多个注解,这些注解同时生效。
public class People {
@NotNull(message = "姓名不能是null")
@Length(min = 2,max = 6,message = "长度应该是2-6位")
private String name;
private String age;
// 省略Getter和Setter
}
编写控制单元,控制单元中必须添加@Valid注解,否则校验不生效。
@RequestMapping("/valid")
public String testValid(@Valid People peo){
System.out.println(peo);
return "/abc.jsp";
}
五、总结
@Controller 定义控制器
@RestController 等效于@Controller+@ResponseBody
@ControllerAdvice 基于Spring框架的异常通知实现
@RequestMapping 定义映射路径
@PutMapping 接收put请求,整体更新
@PatchMapping 属于对Put的补充,局部更新
@DeleteMapping 接收delete请求
@PostMapping 接收post请求
@GetMapping 接收get请求
@ResponseBody 把返回值转换为json并设置到响应体中
@CrossOrigin 允许跨域,在响应头添加Access-Control-Allow-Origin属性
@ExceptionHandler 异常处理
@RequestParam 处理请求参数
@RequestHeader 接收请求头
@RequestBody 把请求体数据转换为对象
@PathVariable 获取restful请求参数
@SessionAttribute 获取Session作用域的值
name:作用域值的名称。如果没有设置name按照参数名称获取。
required:默认为true,表示作用域中必须有这个属性,如果没有报异常。设置为false,如果没有返回null。