pom.xml:Maven构建说明文件。
DemoApplication.java:一个带有main()方法的类,用于启动应用程序(关键)。
DemoApplicationTests.java:一个空的Junit测试类,它加载了一个使用Spring Boot字典配置功能的Spring应用程序上下文。
application.properties:一个空的properties文件,你可以根据需要添加配置属性。
创建TestController类,添加如下代码。
@RestController
@EnableAutoConfiguration
public class TestController {
@RequestMapping("/")
public String test() {
return "Hello world";
}
}
在DemoApplication.java 文件点击右键运行main方法(也可以另外一种启动方式:
mvn spring-boot:run -Dspring.profiles.active=dev
),之后运行http://localhost:8080/就会看到Hello world
了。
- 注意一点:DemoApplication这个启动类必须放在最外层,要不会抱一个错误
Whitelabel Error Page
,详细解释也可以看官网http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-structuring-your-code
接下来我们做一下代码规范要求,以后都按照这种格式统一书写。
以下是基础jar文件:
com.lulj
bruce-bean
1.0.0-SNAPSHOT
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-logging
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.1
tk.mybatis
mapper-spring-boot-starter
1.2.4
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-starter-freemarker
org.apache.commons
commons-pool2
2.5.0
commons-io
commons-io
2.5
com.alibaba
fastjson
1.2.47
net.sf.json-lib
json-lib
2.4
jdk15
mysql
mysql-connector-java
com.alibaba
druid
1.1.0
org.projectlombok
lombok
1.16.10
com.github.pagehelper
pagehelper-spring-boot-starter
1.2.3
org.apache.maven.plugins
maven-compiler-plugin
2.3.2
在resources目录下新建application.properties或者application.yml配置文件,本文使用properties,添加如下配置:
#公共配置与profiles选择无关
mybatis.typeAliasesPackage=com.example.demo.domain
mybatis.mapperLocations=classpath*:com/example/demo/dao/**/*Mapper.xml
configuration.cacheEnabled=true
configuration.useGeneratedKeys=true
configuration.defaultExecutorType=REUSE
configuration.log-imp=LOGBACK
#驼峰标识
configuration.mapUnderscoreToCamelCase=true
configuration.jdbcTypeForNull=NULL
#sql日志
logging.level.com.example.demo..dao=DEBUG
###########################################开发配置###########################################
#端口
server.port=8080
#项目名称
server.servlet.context-path=/demo
#服务名称
spring.application.name=demo
###mysql驱动配置信息
spring.datasource.url=jdbc:mysql://192.168.179.191:3306/wx?useUnicode=true&useSSL=false&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 连接池的配置信息
spring.datasource.filters=stat
spring.datasource.maxActive=20
spring.datasource.initialSize=1
spring.datasource.maxWait=60000
spring.datasource.minIdle=1
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=select 'x'
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20
########分页#######
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
pagehelper.offset-as-page-num=true
pagehelper.row-bounds-with-count=true
SpringBoot 的日志文件放在resources目录下,在resources目录下新建logback.xml.
demo
${log.dir}/log_error.log
${log.dir}/error/${log.name}-error-%d{yyyy-MM-dd}.%i.log
2MB
true
[%date{ISO8601}] [%-5level] - [%thread] [%X{requestId}] [%logger] [%X{akkaSource}] - %msg
%rootException %n
utf-8
error
ACCEPT
DENY
${log.dir}/${log.name}_warn.log
${log.dir}/warn/${log.name}-warn-%d{yyyy-MM-dd}.%i.log
2MB
true
[%date{ISO8601}] [%-5level] - [%thread] [%X{requestId}] [%logger] [%X{akkaSource}] - %msg
%rootException %n
utf-8
warn
ACCEPT
DENY
${log.dir}/${log.name}_info.log
${log.dir}/info/${log.name}-info-%d{yyyy-MM-dd}.%i.log
2MB
true
[%date{ISO8601}] [%-5level] - [%thread] [%X{requestId}] [%logger] [%X{akkaSource}] - %msg
%rootException %n
utf-8
info
ACCEPT
DENY
%black() %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight([%-5level]) %cyan([%X{requestId}]) %boldMagenta([%logger]) [%X{akkaSource}] - %cyan(%msg
%rootException %n)
utf-8
debug
@Aspect
@Order(-99)
@Configuration
@Slf4j
public class LogConfig {
@Pointcut("execution(* com.example.demo.controller..*.*(..))," +
"execution(* com.example.demo.api..*.*(..))")
public void executionService() {
}
@Before(value = "executionService()")
public void doBefore(JoinPoint joinPoint) {
String requestId = String.valueOf(UUID.randomUUID());
MDC.put("requestId", requestId);
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("HTTP URL : " + request.getRequestURL().toString());
log.info("HTTP METHOD : " + request.getMethod());
log.info("IP : " + IPAddrUtil.localAddress());
log.info("CLASS METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
log.info("PARAMS : " + Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(pointcut = "executionService()", returning = "returnValue")
public void doAfterReturning(Object returnValue) {
log.info("=====>@AfterReturning:The response parameter is:{}", returnValue);
MDC.clear();
}
@Around("executionService()")
public Object timeAround(ProceedingJoinPoint joinPoint) {
long startTime = System.currentTimeMillis();
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
log.error("=====>Counts the elapsed time of a method execution to surround notification errors:", e);
}
long endTime = System.currentTimeMillis();
log.info("=====>Processing this request takes time:{} ms", endTime - startTime);
return obj;
}
}
首先pom文件要引入shiro的jar包,如下:
org.apache.shiro
shiro-spring
1.4.0
引入模板引擎freemarker:
org.springframework.boot
spring-boot-starter-freemarker
net.mingsoft
shiro-freemarker-tags
0.1
package com.example.demo.config;
import com.example.demo.core.shiro.MyShiroRealm;
import com.example.demo.domain.properties.RedisProperties;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author lu
*/
@ConditionalOnWebApplication
@Configuration
@EnableConfigurationProperties({RedisProperties.class})
public class ShiroConfig {
@Bean
public FilterRegistrationBean delegatingFilterProxy() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login/loginPage");
shiroFilterFactoryBean.setSuccessUrl("/login/main");
shiroFilterFactoryBean.setUnauthorizedUrl("/login/500");
Map filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login/**", "anon");
filterChainDefinitionMap.put("/res/** ", "anon");
filterChainDefinitionMap.put("/**", "authc");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
// @Bean
// public Realm shiroRealm(HashedCredentialsMatcher matcher) {
// MyShiroRealm myShiroRealm = new MyShiroRealm();
// myShiroRealm.setCredentialsMatcher(matcher);
// return myShiroRealm;
// }
@Bean
public Realm shiroRealm() {
return new MyShiroRealm();
}
@Bean
public SecurityManager securityManager(RedisProperties commonProperties) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRememberMeManager(rememberMeManager());
securityManager.setSessionManager(sessionManager(commonProperties));
securityManager.setCacheManager(cacheManager(commonProperties));
securityManager.setRealm(shiroRealm());
return securityManager;
}
// @Bean
// public SecurityManager securityManager(RedisProperties commonProperties) {
// DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// securityManager.setRememberMeManager(rememberMeManager());
// securityManager.setSessionManager(sessionManager(commonProperties));
// securityManager.setCacheManager(cacheManager(commonProperties));
// securityManager.setRealm(shiroRealm(hashedCredentialsMatcher()));
// return securityManager;
// }
@Bean
public SimpleCookie rememberCookie() {
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
return simpleCookie;
}
@Bean
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberCookie());
cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
return cookieRememberMeManager;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(0);
return credentialsMatcher;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 开启Shiro的注解支持
* 比如:@RequireRoles @RequireUsers
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public SessionManager sessionManager(RedisProperties commonProperties) {
MySessionManager mySessionManager = new MySessionManager();
mySessionManager.setSessionDAO(redisSessionDAO(commonProperties));
// mySessionManager.setCacheManager(cacheManager());
mySessionManager.setSessionIdUrlRewritingEnabled(true);
return mySessionManager;
}
@Bean
public RedisManager redisManager(RedisProperties commonProperties) {
RedisManager redisManager = new RedisManager();
redisManager.setHost(commonProperties.getHost());
redisManager.setPort(commonProperties.getPort());
redisManager.setTimeout(commonProperties.getTimeout());
redisManager.setPassword(commonProperties.getPassword());
return redisManager;
}
/**
* redis实现缓存
*
* @return
*/
@Bean
public RedisCacheManager cacheManager(RedisProperties commonProperties) {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager(commonProperties));
return redisCacheManager;
}
/**
* 使用Redis实现 shiro sessionDao
*
* @return
*/
@Bean
public RedisSessionDAO redisSessionDAO(RedisProperties commonProperties) {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager(commonProperties));
return redisSessionDAO;
}
}
package com.example.demo.config;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
public class MySessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "X-Token";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public MySessionManager() {
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
//获取请求头中X-Token中保存的sessionId
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if (!StringUtils.isEmpty(id)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
} else {
//否则默认从cookie中获取sessionId
return super.getSessionId(request, response);
}
}
}
package com.example.demo.domain.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedisProperties {
private String host;
private int port;
private String password;
private int timeout;
private int database;
}
package com.example.demo.core.shiro;
import com.example.demo.domain.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* shiroRealm 重写权限过滤
*
* @author lu
*/
@Component
public class MyShiroRealm extends AuthorizingRealm {
/**
* 登录信息和用户验证信息验证(non-Javadoc)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal(); // 得到用户名
String password = new String((char[]) token.getCredentials()); // 得到密码
if (null != username && null != password) {
return new SimpleAuthenticationInfo(username, password, getName());
} else {
return null;
}
}
/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法(non-Javadoc)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
User user = null;
try {
user = AuthUtil.getCurrentUser();
} catch (Exception e) {
e.printStackTrace();
}
SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
simpleAuthorInfo.addStringPermissions(getPermCodes(user));
return simpleAuthorInfo;
}
/**
* 获取权限,string存放的是权限编码
*
* @param user
* @return
*/
private List getPermCodes(User user) {
//TODO 你的权限编码处理
return null;
}
}
package com.example.demo.core.shiro;
import com.example.demo.domain.User;
import com.lulj.base.json.FastjsonUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
/**
* 用户公共类
*
* @author lu
*
*/
public class AuthUtil {
/**
* 获取当前用户
*
* @return
*/
public static User getCurrentUser() throws Exception {
User user;
Subject sub = SecurityUtils.getSubject();
Session session = sub.getSession();
Object userJson = session.getAttribute("session_user");
if (userJson != null) {
user = FastjsonUtils.jsonToBean(User.class, userJson.toString());
} else {
return null;
}
return user;
}
}
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.5
Generate MyBatis Artifacts
deploy
generate
org.mybatis.generator
mybatis-generator-core
1.3.5
com.oracle
ojdbc6
12.1.0.2.0
system
${basedir}/lib/ojdbc6.jar
src/main/resources/mybatis-generator/generatorConfigOracle.xml
true
true
在resources下新建mybatis-generator并引入generatorConfigOracle.xml
mybatisGeneratorinit.properties
###generatorConfigOracle.xml
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@118.24.110.49:1521:xe
jdbc.username=
jdbc.password=
#表名
lulj.tableName=
#生成实体名
lulj.domainObjectName=
#生成包路径
lulj.com=
在src下新建assembly.xml内容如下:
bin
tar.gz
zip
dir
false
src/assembly/conf
conf
0644
${profile.dir}
conf
*.xml
*.properties
**/*.xml
**/*.properties
0644
src/assembly/bin
bin
0755
src/assembly/logs
logs
0644
${project.build.directory}
lib
*.jar
脚本参考:https://www.jianshu.com/p/719133b1bad5
org.apache.maven.plugins
maven-assembly-plugin
src/assembly/assembly.xml
make-assembly
package
single
src/main/resources
**/*.*
**/*.ttf
**/*.woff
true
src/main/resources
false
**/*.ttf
**/*.woff