一.Spring
1.Bean配置、管理
配置 beans.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean就是java对象的实体类 由spring容器创建和管理 -->
<!-- bean 工厂 -->
<!-- <bean name="hello" class="cn.spring.bean.Hello">
<property name="name" value="张三"></property>
</bean> -->
<bean id="userdao" class="cn.spring.dao.userdao" /> <-- id随意起名 class包名 -->
<bean id="userservise" class="cn.spring.serise.userservise">
<property name="userDao" ref="userdao"></property> <-- name是servise中的方法名 class包名 -->
</bean>
</beans>
java -- 此段为创建hello对象的(对应注释中的代码)
public static void main(String[] args) {
//解析beans.xml文件 生成相应的bean对象
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Hello ho = (Hello) ac.getBean("hello");
ho.show();
}
hello class
package cn.ioc.bean;
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("hello"+name);
}
}
2.Ioc、Aop
IOC:控制反转也叫依赖注入。利用了工厂模式
将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类(假设这个类名是A),分配的方法就是调用A的setter方法来注入,而不需要你在A里面new这些bean了。
AOP:面向切面编程。(Aspect-Oriented Programming)
AOP可以说是对OOP(面向对象)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。
实现AOP的技术,主要分为两大类:
一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码.
@Aspect
@Component
public class SignAop {
@Pointcut("execution(public * cn.wbnull.springbootdemo.controller.*.*(..))")
private void signAop() {
}
@Before("signAop()")
public void doBefore(JoinPoint joinPoint) throws Exception {
//code
}
@AfterReturning(value = "signAop()", returning = "params")
public JSONObject doAfterReturning(JoinPoint joinPoint, JSONObject params) {
//code
}
}
3.事务
1、事务认识
事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。
(1)原子性(Atomicity)
事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
(2)一致性(Consistency)
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
(3)隔离性(Isolation)
指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
(4)持久性(Durability)
指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
2、事务的传播特性
事务传播行为就是多个事务方法调用时,如何定义方法间事务的传播。Spring定义了7中传播行为:
(1)propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。
(2)propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
(3)propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
(4)propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
(5)propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
(6)propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
(7)propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。
3、事务的隔离级别
(1)read uncommited:是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。
(2)read commited:保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。
(3)repeatable read:这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。
(4)serializable:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读
(5)脏读、不可重复读、幻象读概念说明:
a.脏读:指当一个事务正字访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
b.不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。
c.幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中)
4、事务几种实现方式
(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务
以用户购买股票为例
新建用户对象、股票对象、以及dao、service层
/**
* 账户对象
*
*/
public class Account {
private int accountid;
private String name;
private String balance;
public int getAccountid() {
return accountid;
}
public void setAccountid(int accountid) {
this.accountid = accountid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBalance() {
return balance;
}
public void setBalance(String balance) {
this.balance = balance;
}
}
/**
* 股票对象
*
*/
public class Stock {
private int stockid;
private String name;
private Integer count;
public Stock() {
super();
}
public Stock(int stockid, String name, Integer count) {
super();
this.stockid = stockid;
this.name = name;
this.count = count;
}
public int getStockid() {
return stockid;
}
public void setStockid(int stockid) {
this.stockid = stockid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
DAO层
public interface AccountDao {
void addAccount(String name,double money);
void updateAccount(String name,double money,boolean isbuy);
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void addAccount(String name, double money) {
String sql = "insert account(name,balance) values(?,?);";
this.getJdbcTemplate().update(sql,name,money);
}
@Override
public void updateAccount(String name, double money, boolean isbuy) {
String sql = "update account set balance=balance+? where name=?";
if(isbuy)
sql = "update account set balance=balance-? where name=?";
this.getJdbcTemplate().update(sql, money,name);
}
}
public interface StockDao {
void addStock(String sname,int count);
void updateStock(String sname,int count,boolean isbuy);
}
public class StockDaoImpl extends JdbcDaoSupport implements StockDao {
@Override
public void addStock(String sname, int count) {
String sql = "insert into stock(name,count) values(?,?)";
this.getJdbcTemplate().update(sql,sname,count);
}
@Override
public void updateStock(String sname, int count, boolean isbuy) {
String sql = "update stock set count = count-? where name = ?";
if(isbuy)
sql = "update stock set count = count+? where name = ?";
this.getJdbcTemplate().update(sql, count,sname);
}
}
Service
public interface BuyStockService {
public void addAccount(String accountname, double money);
public void addStock(String stockname, int amount);
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException;
}
public class BuyStockServiceImpl implements BuyStockService{
private AccountDao accountDao;
private StockDao stockDao;
@Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money);
}
@Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount);
}
@Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy);
}
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public StockDao getStockDao() {
return stockDao;
}
public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
}
}
public class BuyStockException extends Exception {
public BuyStockException() {
super();
}
public BuyStockException(String message) {
super(message);
}
}
(1)基于 TransactionProxyFactoryBean的声明式事务管理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-aop-4.2.xsd
">
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="accountDao" class="transaction.test2.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="stockDao" class="transaction.test2.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="buyStockService" class="transaction.test2.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务代理工厂 -->
<!-- 生成事务代理对象 -->
<bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="myTracnsactionManager"></property>
<property name="target" ref="buyStockService"></property>
<property name="transactionAttributes">
<props>
<!-- 主要 key 是方法
ISOLATION_DEFAULT 事务的隔离级别
PROPAGATION_REQUIRED 传播行为
-->
<prop key="add*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
<!-- -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
<prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-BuyStockException</prop>
</props>
</property>
</bean>
</beans>
测试入口
public static void main(String[] args) {
String resouce = "transaction/test2/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
BuyStockService buyStockService = (BuyStockService) applicationContext.getBean("serviceProxy");
// buyStockService.openAccount("小郑", 5000);
// buyStockService.openStock("知晓科技", 0);
try {
buyStockService.buyStock("小郑", 1000, "知晓科技", 100);
} catch (BuyStockException e) {
e.printStackTrace();
}
}
发生异常账户金额不能减,股票不能增加
(2)基于 @Transactional 的声明式事务管理
其他类不做改变,只改变购买股票接口实现类和配置文件
public class BuyStockServiceImpl implements BuyStockService{
private AccountDao accountDao;
private StockDao stockDao;
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
@Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money);
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
@Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount);
}
public BuyStockServiceImpl() {
// TODO Auto-generated constructor stub
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=BuyStockException.class)
@Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy);
}
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public StockDao getStockDao() {
return stockDao;
}
public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
}
}
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="accountDao" class="transaction.test3.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="stockDao" class="transaction.test3.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="buyStockService" class="transaction.test3.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="myTracnsactionManager"/>
可以看出,使用@Transactional注解的方式配置文件要简单的多,将事务交给事务注解驱动。它有个缺陷是他会把所有的连接点都作为切点将事务织入进去,显然只需要在buyStock()方法织入事务即可。下面看看最后一种实现,它就可以精准的织入到指定的连接点
(3)基于Aspectj AOP配置事务
public class BuyStockServiceImpl implements BuyStockService{
private AccountDao accountDao;
private StockDao stockDao;
@Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money);
}
@Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount);
}
public BuyStockServiceImpl() {
// TODO Auto-generated constructor stub
}
@Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy);
}
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public StockDao getStockDao() {
return stockDao;
}
public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
}
}
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="accountDao" class="transaction.test4.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="stockDao" class="transaction.test4.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="buyStockService" class="transaction.test4.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="myTracnsactionManager">
<tx:attributes>
<!-- 为连接点指定事务属性 -->
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="BuyStockException"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切入点配置 -->
<aop:pointcut expression="execution(* *..service.*.*(..))" id="point"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
执行接口与其他方式一样。
4、权限控制
1.AOP简介
AOP,面向切面编程,往往被定义为促使软件系统实现关注点的分离的技术。系统是由许多不同的组件所组成的,每一个组件负责一块特定的功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件
下面介绍一下AOP相关的术语:
通知: 通知定义了切面是什么以及何时使用的概念。Spring 切面可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能。
后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
返回通知(After-returning):在目标方法成功执行之后调用通知。
异常通知(After-throwing):在目标方法抛出异常后调用通知。
环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
连接点:是在应用执行过程中能够插入切面的一个点。
切点: 切点定义了切面在何处要织入的一个或者多个连接点。
切面:是通知和切点的结合。通知和切点共同定义了切面的全部内容。
引入:引入允许我们向现有类添加新方法或属性。
织入:是把切面应用到目标对象,并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期中有多个点可以进行织入:
编译期: 在目标类编译时,切面被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标加载到JVM时被织入。这种方式需要特殊的类加载器(class loader)它可以在目标类被引入应用之前增强该目标类的字节码。
运行期: 切面在应用运行到某个时刻时被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的。
2.编写Spring AOP的aspect类
package com.sxk.aop;
import com.sxk.entity.Token;
import com.sxk.service.AuthorityService;
import com.sxk.service.TokenService;
import org.apache.commons.fileupload.RequestContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
/**
* Created by stonegeek on 2017/3/4.
*/
@Aspect
public class AroundTest {
@Autowired
TokenService tokenService;
@Autowired
AuthorityService authorityService;
@Pointcut("execution(public * com.sxk.controller.testcontroller.*(..))")
public void testaround(){}
@Around("testaround()")
public Object test(ProceedingJoinPoint jp) throws Throwable{
System.out.println("开始验证Token权限。。。。");
HttpServletRequest request= ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
String tokenName=this.getToken(request);
String url=this.getURL(request);
String method=this.getMethod(request);
System.out.println("Token为:"+tokenName);
System.out.println("URL为:"+url);
System.out.println("Method为:"+method);
Token token=tokenService.findByTokenName(tokenName);
if(token==null)
return "{'result':'Token not exsits'}";
Timestamp creatTime=token.getCreateTime();
int len=token.getEffectiveTime();
Timestamp timeNow=new Timestamp(new Date().getTime());
List<String> allApi=null;
if((creatTime.getTime()+len*1000*60)>=timeNow.getTime()){
allApi=authorityService.getAPI(tokenName);
System.out.println(allApi);
if(allApi!=null&&allApi.contains(url)){
System.out.println("Token验证通过!!!");
return jp.proceed();
}else {
System.out.println("验证失败!!!");
return "{'result':'No authority for this API!!'}";
}
}else {
System.out.println("The Token is Timeout");
return "{'result':'The Token is Timeout!!'}";
}
}
public String getToken(HttpServletRequest request){
return request.getHeader("token");
}
public String getURL(HttpServletRequest request){
return request.getRequestURI();
}
public String getMethod(HttpServletRequest request){
return request.getMethod();
}
}
代码详解:
在管理系统调用后台接口之前,会进行拦截,拦截方法是通过((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()拿到request,在这个request的headers中会有一个key-value(前后台约定的),key为token,value为tokenName,此tokenName为UUID,然后通过这个tokenName从数据库中查询是否有此token,没有的话将返回token not exists字样,有的话 则进行判断此token是否过期,token表中存有token创建时间,还有有效时间,token过期的话,返回the token is timeout!,token有效的话再通过tokenName查询权限表此token的所有允许的API,再对此request和API进行比对,如果包含则允许请求资源,否则返回no authority for this api。
3.登录业务实现类
package com.sxk.service.impl;
import com.sxk.dao.TokenMapper;
import com.sxk.dao.UserMapper;
import com.sxk.service.Login_Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.Date;
import java.util.UUID;
import com.sxk.entity.User;
import com.sxk.entity.Token;
/**
* Created by stonegeek on 2017/3/5.
*/
@Service("login_ServiceImpl")
public class Login_ServiceImpl implements Login_Service {
int effectTime=200;
@Autowired
private UserMapper userMapper;
@Autowired
private TokenMapper tokenMapper;
@Override
public String login(String userName, String password) {
String json=null;
System.out.println("【认证中心】得到用户名和密码分别为:"+userName+","+password);
User user=userMapper.login(userName,password);
System.out.println(user);
Token token;
if (user!=null) {
System.out.println("【认证中心】用户名、密码验证通过!");
UUID tokenName = UUID.randomUUID();
token = new Token();
token.setLoginName(userName);
token.setTokenName(tokenName.toString());
Timestamp timeNow = new Timestamp(new Date().getTime());
token.setCreateTime(timeNow);
token.setEffectiveTime(effectTime);
System.out.println("别再出错了");
if (tokenMapper.findByLoginName(userName) == null) {
tokenMapper.insert(token);
} else {
tokenMapper.updateByPrimaryKeySelective(token);
}
json = "{\"token\":\"" + tokenName.toString() + "\"}";
}else{
json="{\"token\":\"false\"}";
}
System.out.println(json);
return json;
}
}
代码详解:
首先,登录时给了username和password,然后根据这两个字段查询数据库是否有此用户,或者用户的密码是否正确,通过之后,会根据将此username作为loginname存到token表中,于此同时还有一个UUID生成作为tokenname,creatime、effectTime一同存到token表中,当然此操作是有条件的,先根据tokenname判断token表中是否有此token,没有的话在进行insert,有的话则修改token的有效时间和创建时间。
4.AOP配置文件
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="aroundTest" class="com.sxk.aop.AroundTest" />
5.token实体类
package com.sxk.entity;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by lenovo on 2017/3/2.
*/
public class Token implements Serializable {
private Integer tokenId;
private String tokenName;
private Timestamp createTime;
private Integer effectiveTime;
private String loginName;
public Integer getTokenId() {
return tokenId;
}
public void setTokenId(Integer tokenId) {
this.tokenId = tokenId;
}
public String getTokenName() {
return tokenName;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public Integer getEffectiveTime() {
return effectiveTime;
}
public void setEffectiveTime(Integer effectiveTime) {
this.effectiveTime = effectiveTime;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
}
在Spring Boot中使用Spring Security实现权限控制
4.Spring、JPA整合
二.Hibernate
1.ORM与持久化映射
2.延迟加载、性能优化
3.HQL查询、条件查询、SQL查询
4.二级缓存与查询缓存
三.Mybatis
四.SpringMVC框架