1.Mybatis中的注解
@param
使用param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以param1,param2…为键,以参数为值;只需要通过${}和#{}访问map集合的键就可以获取相对应的值
注意${}需要手动加单引号
public interface TestMapper{
void TestByParam(@Param("username") String username,@Param("password") String password);
}
<!--User TestByParam(@Param("username") String username, @Param("password") String password)-->
<select id="TestByParam" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>fr
2.Spring中的注解
(1)基于注解管理bean
以上四个注解功能一致,@Controller、@Service、@Repository都是由@Component扩展出来的
但是对于开发人员来说,可以通过不同的注解标记不同的组件
@Component
标记一个普通组件
@Component
public class User{}
@Controller (Servlet)
标记一个控制层组件
@Controller
public class UserController
@Service (Service)
标记一个业务层组件
@Service
public class UserServiceImpl{}
@Repository (Dao)
标记一个持久层组件
@Repository
public class UserDaoImpl{}
注意:通过标记和扫描被IOC容器管理的bean都有默认的id,类名的小驼峰,即类名的首字母小写的结果
若需要自定义bean的id,此时可以通过@Controller、@Service、@Repository、@Component的value属性设置
@Autowired
基于注解的自动装配
@Autowired注解可以标记在成员变量、set方法、有参构造上,建议标记在成员变量上,此时不需要设置set方法和有参构造
@Autowired
private UserService userService;
原理:
(1) @Autowired注解默认使用byType的方式完成自动装配,即根据类型在IOC容器中匹配某个bean为当前的属性赋值
(2) 若通过byType的方式,在IOC容器中没有匹配到任何一个bean,此时报错:NoSuchBeanDefinitionException
(3) 导致NoSuchBeanDefinitionException是因为在@Autowired中,有属性required,默认值为true,表示当前的属性必须完成自动装配,若装配失败则报错NoSuchBeanDefinitionException
此时可以将required设置为false,则表示能装配则装配,若无法装配,则使用默认值,一般不用
(4) 若在IOC容器中匹配到了多个bean,此时会自动切换为byName,即将需要赋值的成员变量的名字作为bean的id在IOC容器中匹配
(5) 若通过byName没有匹配到任何一个bean,即IOC容器中有多个类型匹配的bean,但是任何一个bean的id和要赋值的成员变量的名字都不一致
此时报错:NoUniqueBeanDefinitionException,可以在成员变量上添加@Qualifier注解,通过通过该注解的value属性设置某个bean的id,将bean为当前属性赋值
@Qualifier
@Autowired
@Qualifier("userServiceImpl")
private UserService userService;
即IOC容器中有多个类型匹配的bean,但是任何一个bean的id和要赋值的成员变量的名字都不一致,通过该注解的value属性设置某个bean的id,将bean为当前属性赋值
(2)AOP中的注解
@Aspect
将组件标记为一个切面
@Component
@Aspect
public class LoggerAspect {}
@Order
切面的优先级
通过value属性设置一个正整数,值越小优先级越高
@Component
@Aspect
@Order(2)
public class LoggerAspect{
@Before("pointCut()")
public void beforeAdviceMethod(JoinPoint joinPoint){
//获取连接点所对应方法的方法名
String methodName = joinPoint.getsignature().getName();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("beforeAdvice-->前置通知,方法:" + methodName + ",参数:" + Arrays.toString(args));
}
}
@Component
@Aspect
@Order(1)
public class ValidateAspect{
//验证计算机,要求在日志之前
@Before"com.swz.LoggerAspect.pointCut()"
public void beforeAdviceMethod(JoinPoint joinPoint){
System.Out.Println("ValidateAspect-->前置通知")
}
}
@Pointcut
设置一个公共的切入点表达式
@Component
@Aspect
public class LoggerAspect{
//可以使用在其他类,不过要写全类名
@Pointcut("execution( * com.swz.CalculatorImpl.*(..) )")
public void pointCut(){}
//通过切入点表达式定位切入点
@Before("pointCut()")
public void beforeAdviceMethod(JoinPoint joinPoint){}
}
public class ValidateAspect{
@Before"com.swz.LoggerAspect.pointCut()"
public void beforeAdviceMethod(JoinPoint joinPoint){}
}
切入点表达式的语法,即(@Before,@After中括号内写的内容)
1.execution( 访问修饰符 返回值类型 包类方法(参数类型) )
2.execution( * com.swz.CalculatorImpl.*(…) )
- 用*号代替“权限修饰符”和“返回值”部分表示“权限修饰符”和“返回值”不限
- 在包名的部分,一个“*”号只能代表包的层次结构中的一层,表示这一层是任意的。
- 例如:*.Hello匹配com.Hello,不匹配com.atguigu.Hello
- 在包名的部分,使用“*…”表示包名任意、包的层次深度任意
- 在类名的部分,类名部分整体用*号代替,表示类名任意
- 在类名的部分,可以使用*号代替类名的一部分
- 例如:*Service匹配所有名称以Service结尾的类或接口
- 在方法名部分,可以使用*号表示方法名任意
- 在方法名部分,可以使用*号代替方法名的一部分
- 例如:*Operation匹配所有方法名以Operation结尾的方法
- 在方法参数列表部分,使用(…)表示参数列表任意
- 在方法参数列表部分,使用(int,…)表示参数列表以一个int类型的参数开头
- 在方法参数列表部分,基本数据类型和对应的包装类型是不一样的
- 切入点表达式中使用 int 和实际方法中 Integer 是不匹配的
- 在方法返回值部分,如果想要明确指定一个返回值类型,那么必须同时写明权限修饰符
通知
在切面中将横切关注点封装一个方法,使用指定的注解将其标记为不同的通知方法
前置通知: 使用@Before标记,在目标对象核心功能之前执行
返回通知: 使用@AfterReturning标记,在目标对象方法的返回值之后执行
异常通知: 使用@AfterThrowing标记,在目标对象方法的catch语句块中执行
后置通知: 使用@After标记,在目标对象方法的finally语句块中执行
环绕通知: 使用Around标记,在目标对象的四个位置执行
@Before
前置通知
@Component
@Aspect
public class LoggerAspect{
//通过切入点表达式定位切入点
@Before("execution(public int com.swz.aop.annotation.CalculatorImpl.*(int, int))")
public void beforeAdviceMethod(JoinPoint joinPoint){
//获取连接点所对应方法的方法名
String methodName = joinPoint.getsignature().getName();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("beforeAdvice-->前置通知,方法:" + methodName + ",参数:" + Arrays.toString(args));
}
}
@AfterReturning
返回通知
@Component
@Aspect
public class LoggerAspect{
//通过切入点表达式定位切入点
@AfterReturning("execution(public int com.swz.aop.annotation.CalculatorImpl.*(int, int))" returning = "result")
public void AfterReturningAdviceMethod(JoinPoint joinPoint , Object result){
//获取连接点所对应方法的方法名
String methodName = joinPoint.getsignature().getName();
System.out.println("AfterReturningAdvice-->返回通知,方法:" + methodName + ",结果:" +result);
}
}
@AfterThrowing
异常通知
@Component
@Aspect
public class LoggerAspect{
//通过切入点表达式定位切入点
@AfterThrowing("execution(public int com.swz.aop.annotation.CalculatorImpl.*(int, int))" throwing = "result")
public void AfterThrowingAdviceMethod(JoinPoint joinPoint , Throwable ex){
//获取连接点所对应方法的方法名
String methodName = joinPoint.getsignature().getName();
System.out.println("AfterThrowingAdvice-->返回通知,方法:" + methodName + ",异常信 息:"+ex);
}
}
@After
后置通知
@Component
@Aspect
public class LoggerAspect{
//通过切入点表达式定位切入点
@After("execution(public int com.swz.aop.annotation.CalculatorImpl.*(int, int))")
public void AfterAdviceMethod(JoinPoint joinPoint){
//获取连接点所对应方法的方法名
String methodName = joinPoint.getsignature().getName();
System.out.println("AfterAdvice-->后置通知,方法:" + methodName + "执行完毕");
}
}
JoinPoint
//JoinPoint获取获取链接点的相关信息
//获取连接点所对应方法的方法名
String methodName = joinPoint.getsignature().getName();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
@Around
环绕通知
@Component
@Aspect
public class LoggerAspect{
@Around("execution(public int com.swz.aop.annotation.CalculatorImpl.*(int, int))")
public void aroundAdviceMethod(ProceedingJoinPoint joinPoint){
Object result = null;
try{
System.out.println("beforeAdvice-->前置通知,方法:" + methodName + ",参数:" + Arrays.toString(args));
joinPoint.procces();
System.out.println("AfterReturningAdvice-->返回通知,方法:" + methodName + ",结 果:"+result);
}catch{
}finally{
}
}
}
(3) Spring整合Junit4,junit5
测试方法在Spring的环境下运行,可以在当前测试类中自动装配IOC容器所管理的对象
@RunWith
设置Junit方法是在什么Junit环境下执行
@ContextConfiguration
设置Spring的配置文件
//指定测试方法在Spring的IOC环境中执行
@RunWith(SpringJUnit4ClassRunner.class)//junit4
//设置IOC容器所对应的配置文件
@ContextConfiguration("classpath:spring-jdbc.xml")
public void Test(){
@Autowired
private JdbcTemplate jdbcTemplate;
}
@Extendwith
//指定测试方法在Spring的IOC环境中执行
@Extendwith(SpringExtension .class)//junit5
//设置IOC容器所对应的配置文件
@ContextConfiguration("classpath:spring-jdbc.xml")
public void Test(){
@Autowired
private JdbcTemplate jdbcTemplate;
}
@SpringJUnitConfig
复合注解
@SpringJUnitConfig(locations = {"classpath:spring-context.xml"})
public void Test(){
@Autowired
private JdbcTemplate jdbcTemplate;
}
(4)基于注解的声明式事务
@Transactional
用法
1、基于注解的声明式事务的实现步骤
a>在配置文件中配置事务管理器
b>开启事务的注解驱动
c>在需要被事务管理的方法上或类上添加注解@Transactional2、@Transactional标记的位置
标记在方法上,则该方法会被事务管理
标记在类上,则类中所有的方法会被事务管理
元注解
@Target({ElementType.TYPE, ElementType.METHOD})//当前注解能标记的位置,表示可以用在类和方法上
@Retention(RetentionPolicy.RUNTIME)//当前注解能保存到哪一个阶段,RUNTIME表示到字节码
@Inherited//表示注解可以被继承
@Documented
public @interface Transactional {}
xml配置
<!--设置数据源事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
开启事务的注解驱动
将使用@Transactional注解标记的方法或类中所有的方法被事务管理器管理
-->
<tx:annotation-driven transaction-manager="transactionManager"/>
注解|事务属性
1.只读
可以通过@Transactional注解的readOnly属性设置事务的只读,默认值为false
若当前事务中全部都是查询操作,就可以设置事务的只读属性,此时会通知数据库,从数据库层面优化当前事务中的操作
注意:若当前事务设置了readOnly=“true”,但是事务中有任何一个增删改操作,则直接报错:Connection is read-only. Queries leading to data modification are not allowed
2.超时
可以通过@Transactional注解的timeout属性设置事务的超时,默认值为-1,即一直等
当设置了事务的超时属性,若事务执行时超过指定时间未执行完毕,则会强制回滚并抛出异常:TransactionTimedOutException
3.回滚策略
可以通过@Transactional注解的rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName属性设置事务的回滚策略
可以通过事务的回滚策略设置导致或不导致事务回滚的异常
声明式事务默认情况下任何的运行时异常都会导致事务的回滚
4.事务属性之隔离级别
可以通过@Transactional注解的isolation属性设置事务的隔离级别
isolation=Isolation.DEFAULT:使用数据库默认的隔离级别
isolation=Isolation.READ_UNCOMMITTED:读未提交
isolation=Isolation.READ_COMMITTED:读已提交
isolation=Isolation.REPEATABLE_READ:可重复读
isolation=Isolation.SERIALIZABLE:序列化
5.事务属性之传播行为
可以通过@Transactional注解的propagation属性设置事务的传播行为
当事务方法A调用事务方法B,对于事务方法B使用A的事务或者B本身的事务,即事务方法被调用时,使用事务的方式就是事务的传播行为
propagation=Propagation.REQUIRED:默认值,使用调用者的事务
propagation=Propagation.REQUIRES_NEW:使用被调用者的事务
@Transactional(
readOnly="true"//只读
timeout= 3//超时
rollbackFor = //导致事务回滚的异常,内容是Class类型
rollbackForClassName //导致事务回滚的异常,内容是字符串类型
noRollbackFor //不导致事务回滚的异常,内容是Class类型
noRollbackForClassName //不导致事务回滚的异常,内容是字符串类型
isolation = Isolation.DEFAULT
propagation=Propagation.REQUIRED
)
2.SpringMVC中的注解
@RequestMapping
1.功能
把浏览器发送的请求和@RequestMapping注解所设置的请求信息进行匹配,若匹配成功,则@RequestMapping所标记的方法就是处理当前请求的方法
2.标记的位置
标记在类上,为标记在方法上的@RequestMapping设置一个前缀的路径
标记在方法上,为需要处理的请求设置一个具体的路径
@Controller
@RequestMapping("/test")
public class TestRequestMapping{
@RequestMapping("/success")//此时的真实路径为/test/success
public String success(){
return "success";
}
}
3.属性
1>value属性
@RequestMapping注解的value属性是通过请求的请求路径匹配请求映射
value属性是字符串数组类型,因此可以设置多个请求的请求路径,由注解所标记的方法可以处理value中所设置的每一个路径所对应的请求
@Controller
@RequestMapping("/test")
public class TestRequestMapping{
@RequestMapping({"/success","/abc"})//此时的真实路径为/test/success|/test/abc
public String success(){
return "success";
}
}
<a th:href="@{/test/success}">测试@RequestMapping注解的value属性</a>
<a th:href="@{/test/abc}">测试@RequestMapping注解的value属性</a>
2>method属性
@RequestMapping注解的method属性是通过请求的请求路径匹配请求映射
method属性是RequestMethod数组类型,因此可以设置多种请求方式,当前注解@RequestMapping注解所标记的方法处理的请求的请求方式只要满足其中一种即可
若@RequestMapping注解的Value属性可以匹配,但是method属性无法匹配此时报错405: Request method ‘GET’ not supported
@Controller
@RequestMapping("/test")
public class TestRequestMapping{
@RequestMapping(
value = {"/success","/abc"}//此时的真实路径为/test/success|/test/abc
method = {RequestMethod.GET,RequestMethod.POST}
)
public String success(){
return "success";
}
}
3>params属性
@RequestMapping注解的params属性是通过请求的请求参数匹配请求映射
若@RequestMapping注解的value属性可以匹配,但是params属性无法匹配,页面报错400
params属性中可以使用四种表达式
param :匹配的请求必须携带请求参数param
!param :匹配的请求一定不能携带请求参数param
param=value:匹配的请求必须携带请求参数param,且值必须为value
param!=value:匹配的请求可以不携带请求参数param,若携带则一定不能为value
@Controller
@RequestMapping("/test")
public class TestRequestMapping{
@RequestMapping(
value = {"/success","/abc"}//此时的真实路径为/test/success|/test/abc
params = {"username","password!=123456"}//必须有用户名且密码不能为123456
)
public String success(){
return "success";
}
}
4>headers属性
headers方法同params,因为头信息就是键值对
若@RequestMapping注解的value属性可以匹配,但是headers属性无法匹配,页面报错404
@Controller
@RequestMapping("/test")
public class TestRequestMapping{
@RequestMapping(
value = {"/success","/abc"}//此时的真实路径为/test/success|/test/abc
headers = "Lock Host"
)
public String success(){
return "success";
}
}
4.SpringMVC支持ant风格的路径
可以在@RequestMapping注解的value属性中,设置路径时使用一些特殊的符号表示特殊的含义
?:任意的单个字符,注意不能匹配?和/
*:任意个数的任意字符,注意不能匹配?和/
星星:任意层数的任意目录,注意不能匹配?,使用**时,前后和中间都不可以有其他内容
@PathVariable
SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过**@PathVariable**注解,将占位符所表示的数据赋值给控制器方法的形参
<a th:href="@{/testRest/1/admin}">测试路径中的占位符-->/testRest</a><br>
@RequestMapping("testRest/1/{username}")
public String testRest(@PathVariable("username") String username){
System.Out.println("username = " + username);
return "success";
}
当占位符内的形参与方法参数的形参一致时可以省略@PathVariable的value值
@RequestMapping("testRest/1/{username}")
public String testRest(@PathVariable String username){
System.Out.println("username = " + username);
return "success";
}
(1)获取请求参数
@RequestParam
@RequestParam是将请求参数和控制器方法的形参创建映射关系
@RequestParam注解一共有三个属性:
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值
<a th:href="@{/param/RequestParam(username='admin')}">
使用RequestParam获取请求参数
</a>
@RequestMapping("/RequestParam")
public String testRequestParam(
@RequestParam(
value = "username",//参数名username
required = true,//表示必须传参数,与defaultValue一起用毫无意义
defaultValue = "aaa"//参数默认值为aaa
) String username){
System.out.println("username = " + username + " password = " + password);
return "success";
}
@RequestHeader
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
<a th:href="@{/param/RequestHeader}">使用RequestHeader获取请求头信息</a>
@RequestMapping("/RequestHeader")
public String testRequestHeader(@RequestHeader("referer") String referer){
System.out.println(referer);
return "success";
}
@CookieValue
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
<a th:href="@{/param/CookieValue}">使用CookieValue获取Cookie信息</a>
@RequestMapping("/CookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String JSESSIONID){
System.out.println(JSESSIONID);
return "success";
}