话不多说:先看 pom.xml 将来有可以修改为 gradle 来管理
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xdf</groupId>
<artifactId>newcrm</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>com.xdf</groupId>
<artifactId>91-master</artifactId>
<version>1.0.0.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
<dependency>
<groupId>com.xdf</groupId>
<artifactId>oracle6</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jexcelapi</groupId>
<artifactId>jxl</artifactId>
<version>2.6.12</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version> <!--可以查查最新版-->
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.2</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6</version>
</dependency>
<!-- tomcat支持 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!--<scope>provided</scope>-->
</dependency>
<!-- jstl标签库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
其中部分jar 属于内部仓库 封装的一些源码,企业用户可查看
先看一下目录结构
看一下配置文件:
在resources 目录下
主体文件为:application.xml
根据不同的环境
在编译时 根据命令产生不同 的war 文件
logging:
config: classpath:logback.xml
path: d:/logs
server:
port: 80
session-timeout: 60
spring:
profiles:
active: dev
mvc:
view:
prefix: /WEB-INF/web/
suffix: .jsp
jpa:
show-sql: true
mybatis:
mapperLocations: classpath:/com/xdf/newcrm/mapper/*.xml
typeAliasesPackage: com.xdf.newcrm.mapper
mapperScanPackage: com.xdf.newcrm.mapper
configLocation: classpath:/mybatis-config.xml
oracle:
datasource:
readSize: 2 #读库个数
type: com.alibaba.druid.pool.DruidDataSource
mapperLocations: classpath:/com/xdf/newcrm/mapper/*.xml
configLocation: classpath:/mybatis-config.xml
write:
url: jdbc:oracle:thin:@110.86.22.10:210:orcl
username: ****
password: ***
driver-class-name: oracle.jdbc.driver.OracleDriver
read01:
url: jdbc:oracle:thin:@110.86.22.10:210:orcl
username: ****
password: *****
driver-class-name: oracle.jdbc.driver.OracleDriver
read02:
url: jdbc:oracle:thin:@110.86.22.10:210:orcl
username: ****
password: ****
driver-class-name: oracle.jdbc.driver.OracleDriver
我们看下 研发环境 application-dev.xml
env:
u2AuthorizeUrl: http://testu2.staff.xdf.cn/index.aspx
u2AccessTokenUrl: http://testu2.staff.xdf.cn/apis/OAuth.ashx
u2LogoutUrl: http://testu2.staff.xdf.cn/Logout.aspx
clientId: 9688
clientSecret: u2test-bd848c88-4b2e-4209-b228-47e33da8fa5c
callbackUrl: http://deviteach.staff.xdf.cn/callback_login
logoffCallbackUrl: /exit.jsp
u2ApiUrl: http://testu2.staff.xdf.cn/apis/usersv2.ashx
u2LoginUrl: http://testu2.staff.xdf.cn/i/ys/index.aspx
u2AppID: 90101
u2AppKey: u2testAppKey#$vs
baseUrl: http://testiteach.staff.xdf.cn
domain: /newcrm
application-prod.xml的内容与application-dev.xml 类似
就不在列举
application.xml 文件 作为主体文件,主要描述公共的内容
异同的内容放在其各自的文件中
在spring boot 2.0中的变化和 1.X有这明显的变化
介绍一下 mybatis 多数据源的配置
package com.xdf.newcrm.config.dbconfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
/**
* 数据库源配置
* @author nieshoujun
*
*/
@Configuration
public class DataSourceConfiguration {
private static Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class);
@Value("${oracle.datasource.type}")
private Class<? extends DataSource> dataSourceType;
/**
* 写库 数据源配置
* @return
*/
@Bean(name = "writeDataSource")
@Primary
@ConfigurationProperties(prefix = "oracle.datasource.write")
public DataSource writeDataSource() {
log.info("-------------------- writeDataSource init ---------------------");
return DataSourceBuilder.create().type(dataSourceType).build();
}
/**
* 有多少个从库就要配置多少个
* @return
*/
@Bean(name = "readDataSource01")
@ConfigurationProperties(prefix = "oracle.datasource.read01")
public DataSource readDataSourceOne() {
log.info("-------------------- read01 DataSourceOne init ---------------------");
return DataSourceBuilder.create().type(dataSourceType).build();
}
@Bean(name = "readDataSource02")
@ConfigurationProperties(prefix = "oracle.datasource.read02")
public DataSource readDataSourceTwo() {
log.info("-------------------- read02 DataSourceTwo init ---------------------");
return DataSourceBuilder.create().type(dataSourceType).build();
}
}
这里面的环境变量
采用层级的方式来读取
@Value("${oracle.datasource.type}")
DataSourceContextHolder.java
package com.xdf.newcrm.config.dbconfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 本地线程,数据源上下文
* @author niejun
*
*/
public class DataSourceContextHolder {
private static Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class);
//线程本地环境
private static final ThreadLocal<String> local = new ThreadLocal<String>();
public static ThreadLocal<String> getLocal() {
return local;
}
/**
* 读库
*/
public static void setRead() {
local.set(DataSourceType.read.getType());
log.info("数据库切换到读库...");
}
/**
* 写库
*/
public static void setWrite() {
local.set(DataSourceType.write.getType());
log.info("数据库切换到写库...");
}
public static String getReadOrWrite() {
return local.get();
}
public static void clear(){
local.remove();
}
}
package com.xdf.newcrm.config.dbconfig;
public enum DataSourceType {
read("read", "从库"),
write("write", "主库");
private String type;
private String name;
DataSourceType(String type, String name) {
this.type = type;
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.xdf.newcrm.config.dbconfig;
import com.github.pagehelper.PageHelper;
import com.xdf.newcrm.common.util.SpringContextUtil;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
@Configuration
@AutoConfigureAfter(DataSourceConfiguration.class)
@MapperScan(basePackages="com.xdf.newcrm.mapper")
public class MybatisConfiguration {
private static Logger log = LoggerFactory.getLogger(MybatisConfiguration.class);
@Value("${oracle.datasource.readSize}")
private String readDataSourceSize;
//XxxMapper.xml文件所在路径
@Value("${oracle.datasource.mapperLocations}")
private String mapperLocations;
// 加载全局的配置文件
@Value("${oracle.datasource.configLocation}")
private String configLocation;
@Autowired
@Qualifier("writeDataSource")
private DataSource writeDataSource;
@Autowired
@Qualifier("readDataSource01")
private DataSource readDataSource01;
@Autowired
@Qualifier("readDataSource02")
private DataSource readDataSource02;
@Bean(name="sqlSessionFactory")
public SqlSessionFactory sqlSessionFactorys() throws Exception {
log.info("-------------------- sqlSessionFactory init ---------------------");
try {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
// sessionFactoryBean.setDataSource(roundRobinDataSouce);
sessionFactoryBean.setDataSource(roundRobinDataSouceProxy());
// 读取配置
sessionFactoryBean.setTypeAliasesPackage("com.xdf.newcrm.bean");
//设置mapper.xml文件所在位置
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(mapperLocations);
sessionFactoryBean.setMapperLocations(resources);
//设置mybatis-config.xml配置文件位置
sessionFactoryBean.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
//添加分页插件、打印sql插件
Interceptor[] plugins = new Interceptor[]{new SqlPrintInterceptor()};
sessionFactoryBean.setPlugins(plugins);
return sessionFactoryBean.getObject();
} catch (IOException e) {
log.error("mybatis resolver mapper*xml is error",e);
return null;
} catch (Exception e) {
log.error("mybatis sqlSessionFactoryBean create error",e);
return null;
}
}
/**
* 分页插件
* @return
*/
@Bean
public PageHelper pageHelper() {
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
p.setProperty("returnPageInfo", "check");
p.setProperty("params", "count=countSql");
pageHelper.setProperties(p);
return pageHelper;
}
/**
* 把所有数据库都放在路由中
* @return
*/
@Bean(name="roundRobinDataSouceProxy")
public AbstractRoutingDataSource roundRobinDataSouceProxy() {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
//把所有数据库都放在targetDataSources中,注意key值要和determineCurrentLookupKey()中代码写的一至,
//否则切换数据源时找不到正确的数据源
targetDataSources.put(DataSourceType.write.getType(), writeDataSource);
targetDataSources.put(DataSourceType.read.getType()+"1", readDataSource01);
targetDataSources.put(DataSourceType.read.getType()+"2", readDataSource02);
final int readSize = Integer.parseInt(readDataSourceSize);
// MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(readSize);
//路由类,寻找对应的数据源
AbstractRoutingDataSource proxy = new AbstractRoutingDataSource(){
private AtomicInteger count = new AtomicInteger(0);
/**
* 这是AbstractRoutingDataSource类中的一个抽象方法,
* 而它的返回值是你所要用的数据源dataSource的key值,有了这个key值,
* targetDataSources就从中取出对应的DataSource,如果找不到,就用配置默认的数据源。
*/
@Override
protected Object determineCurrentLookupKey() {
String typeKey = DataSourceContextHolder.getReadOrWrite();
if(typeKey == null){
// System.err.println("使用数据库write.............");
return DataSourceType.write.getType();
// throw new NullPointerException("数据库路由时,决定使用哪个数据库源类型不能为空...");
}
if (typeKey.equals(DataSourceType.write.getType())){
System.err.println("使用数据库write.............");
return DataSourceType.write.getType();
}
//读库, 简单负载均衡
int number = count.getAndAdd(1);
int lookupKey = number % readSize;
System.err.println("使用数据库read-"+(lookupKey+1));
return DataSourceType.read.getType()+(lookupKey+1);
}
};
proxy.setDefaultTargetDataSource(writeDataSource);//默认库
proxy.setTargetDataSources(targetDataSources);
return proxy;
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
//事务管理
@Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager((DataSource)SpringContextUtil.getBean("roundRobinDataSouceProxy"));
}
}
package com.xdf.newcrm.config.dbconfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
/**
* MyBatis 将mybatis要执行的sql拦截打印出来
*
* @since 1.0.0
*/
@Intercepts
({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class SqlPrintInterceptor implements Interceptor {
private static Log logger = LogFactory.getLog(SqlPrintInterceptor.class);
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameterObject = null;
if (invocation.getArgs().length > 1) {
parameterObject = invocation.getArgs()[1];
}
long start = System.currentTimeMillis();
Object result = invocation.proceed();
String statementId = mappedStatement.getId();
BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
Configuration configuration = mappedStatement.getConfiguration();
String sql = getSql(boundSql, parameterObject, configuration);
long end = System.currentTimeMillis();
long timing = end - start;
if(logger.isInfoEnabled()){
logger.info("执行sql耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" );
logger.info(" "+sql);
}
return result;
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
}
return target;
}
@Override
public void setProperties(Properties properties) {
}
private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) {
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
sql = replacePlaceholder(sql, value);
}
}
}
return sql;
}
private String replacePlaceholder(String sql, Object propertyValue) {
String result;
if (propertyValue != null) {
if (propertyValue instanceof String) {
result = "'" + propertyValue + "'";
} else if (propertyValue instanceof Date) {
result = "'" + DATE_FORMAT.format(propertyValue) + "'";
} else {
result = propertyValue.toString();
}
} else {
result = "null";
}
return sql.replaceFirst("\\?", Matcher.quoteReplacement(result));
}
}
到此为止多数据源部分的配置完毕
下面介绍一下,关于安全部分
Spring boot 2.0 集成了 spring Security 框架
其原理和shiro 很相似
在每次调用时根据提供的权限资源 做认证
配置了额外的拦截器
package com.xdf.newcrm.config;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by niejun on 2017/12/29.
*/
@Component
public class AuthenticationAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
resp.setContentType("application/json;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员!\"}");
out.flush();
out.close();
}
}
package com.xdf.newcrm.config;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Iterator;
/**
* Created by niejun on 2017/12/28.
*/
@Component
public class UrlAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, AuthenticationException {
Iterator<ConfigAttribute> iterator = collection.iterator();
while (iterator.hasNext()) {
ConfigAttribute ca = iterator.next();
//当前请求需要的权限
String needRole = ca.getAttribute();
if ("ROLE_LOGIN".equals(needRole)) {
if (authentication instanceof AnonymousAuthenticationToken) {
throw new BadCredentialsException("未登录");
} else
return;
}
//当前用户所具有的权限
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
if (authority.getAuthority().equals(needRole)) {
return;
}
}
}
return;
// throw new AccessDeniedException("权限不足!");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
package com.xdf.newcrm.config;
import java.util.Collection;
import com.xdf.grow.common.util.UserUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
/**
* Created by niejunon 2017/12/28.
*/
@Component
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
/* @Autowired
MenuService menuService;*/
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
//获取请求地址
String requestUrl = ((FilterInvocation) o).getRequestUrl();
if ("/login_p".equals(requestUrl)) {
return null;
}
/* List<Menu> allMenu = menuService.getAllMenu();
for (Menu menu : allMenu) {
if (antPathMatcher.match(menu.getUrl(), requestUrl)&&menu.getRoles().size()>0) {
List<Role> roles = menu.getRoles();
int size = roles.size();
String[] values = new String[size];
for (int i = 0; i < size; i++) {
values[i] = roles.get(i).getName();
}
return SecurityConfig.createList(values);
}
}
//没有匹配上的资源,都是登录访问
return SecurityConfig.createList("ROLE_LOGIN");*/
/* Object currentuser=UserUtils.getCurrentUser();
if(currentuser instanceof String){
return SecurityConfig.createList("ROLE_LOGIN");
}else{*/
return SecurityConfig.createList(new String[]{"1"});
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}
package com.xdf.newcrm.config;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.xdf.grow.common.util.DateConverter;
/**
* Created by niejun on 2018/5/30.
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DateConverter());
}
@Bean
public ExecutorService executorService() {
return Executors.newCachedThreadPool();
}
}
package com.xdf.newcrm.config;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xdf.grow.common.util.UserUtils;
/**
* Created by niejun on 2018/5/30.
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/* @Autowired
HrService hrService;*/
@Autowired
UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;
@Autowired
UrlAccessDecisionManager urlAccessDecisionManager;
@Autowired
AuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/* auth.userDetailsService(hrService).passwordEncoder(new BCryptPasswordEncoder());*/
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**","/login_p","/index");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);
o.setAccessDecisionManager(urlAccessDecisionManager);
return o;
}
}).and().formLogin().loginPage("/login_p").loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password").permitAll().failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
StringBuffer sb = new StringBuffer();
sb.append("{\"status\":\"error\",\"msg\":\"");
if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
sb.append("用户名或密码输入错误,登录失败!");
} else if (e instanceof DisabledException) {
sb.append("账户被禁用,登录失败,请联系管理员!");
} else {
sb.append("登录失败!");
}
sb.append("\"}");
out.write(sb.toString());
out.flush();
out.close();
}
}).successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
ObjectMapper objectMapper = new ObjectMapper();
String s = "{\"status\":\"success\",\"msg\":" + objectMapper.writeValueAsString(UserUtils.getCurrentUser()) + "}";
out.write(s);
out.flush();
out.close();
}
}).and().logout().permitAll().and().csrf().disable().exceptionHandling().accessDeniedHandler(authenticationAccessDeniedHandler);
}
}
以上几个类主要介绍了 框架结构中的安全部分如何定义
接下来说一下
自定义异常
本文主要介绍一下 关于和框架相关的自定义异常,如果在程序执行过程中 出现了任何的异常
继承
HandlerExceptionResolver
会监听到异常后,并补获 根据 自己定义的 json 格式输出
package com.xdf.newcrm.exception;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* Created by niejunon 2018/1/2.
*/
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse response, Object o, Exception e) {
ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
Map<String, String> map = new HashMap<>();
map.put("status", "error");
if (e instanceof DataIntegrityViolationException) {
map.put("msg", "该角色尚有关联的资源或用户,删除失败!");
}else{
map.put("msg", "操作失败!");
}
mv.addAllObjects(map);
return mv;
}
}
自此项目中几个比较核心的部分都已经叙述完毕
关于jpa 的内容 如何使用 将在下一篇博文中去阐释。