SpringBoot整合jsp,Druid数据监控,与Shiro
一.在SpringBoot项目中, 如何能够使用并运行Jsp页面?
1.添加相应jar包坐标
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- jasper:SpringBoot对jsp的支持 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
2.配置视图解析器application.yml
spring: #配置应用名,数据库连接参数
mvc:
view: #视图解析器
prefix: /WEB-INF/page/
suffix: .jsp
3.直接放在resource目录下或者webapp目录下
二. 如何对spring boot项目配置druid数据源和数监控?
1.添加坐标
<!--Alibaba DataBase Connection Pool -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.23</version>
</dependency>
<!--MyBatis And Spring Integration Starter :令@MapperScan生效 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
2.全局配置文件
spring:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/my_exam_test?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
# 初始化时建立物理连接连接的个数
initialSize: 5
# 最小连接池数量
minIdle: 5
# 最大连接池数量
maxActive: 20
# 获取连接时最大等待时间(ms),即60s
maxWait: 60000
# 1.Destroy线程会检测连接的间隔时间;2.testWhileIdle的判断依据
timeBetweenEvictionRunsMillis: 60000
# 最小生存时间ms
minEvictableIdleTimeMillis: 600000
maxEvictableIdleTimeMillis: 900000
# 用来检测连接是否有效的sql
validationQuery: SELECT 1 FROM DUAL
# 申请连接时执行validationQuery检测连接是否有效,启用会降低性能
testOnBorrow: false
# 归还连接时执行validationQuery检测连接是否有效,启用会降低性能
testOnReturn: false
# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,
# 执行validationQuery检测连接是否有效,不会降低性能
testWhileIdle: true
# 是否缓存preparedStatement,mysql建议关闭
poolPreparedStatements: false
#过滤并统计SQL语句
filters: stat,wall,log4j
# 合并多个DruidDataSource的监控数据
useGlobalDataSourceStat: true
更多参数配置
#配置数据源
spring.datasource.url=jdbc:mysql://106.14.xx.xx:3306/test
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.username=123456
spring.datasource.druid.password=123456
1 # 下面为连接池的补充设置,应用到上面所有数据源中
2 # 初始化大小,最小,最大
3 spring.datasource.druid.initial-size=5
4 spring.datasource.druid.min-idle=5
5 spring.datasource.druid.max-active=20
6 # 配置获取连接等待超时的时间
7 spring.datasource.druid.max-wait=60000
8 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
9 spring.datasource.druid.time-between-eviction-runs-millis=60000
10 # 配置一个连接在池中最小生存的时间,单位是毫秒
11 spring.datasource.druid.min-evictable-idle-time-millis=300000
12 spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
13 spring.datasource.druid.test-while-idle=true
14 spring.datasource.druid.test-on-borrow=false
15 spring.datasource.druid.test-on-return=false
16 # 打开PSCache,并且指定每个连接上PSCache的大小
17 spring.datasource.druid.pool-prepared-statements=true
18 spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
19 # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
20 #spring.datasource.druid.filter-class-names=com.alibaba.druid.filter.stat.StatFilter
21 #spring.datasource.druid.filter-class-names=com.alibaba.druid.wall.WallFilter
22 #spring.datasource.druid.filter-class-names=com.alibaba.druid.filter.logging.Log4jFilter,com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter
23 # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
24 #spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
25 #spring.datasource.druid.connect-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
26 # 合并多个DruidDataSource的监控数据
27 #spring.datasource.useGlobalDataSourceStat=true
28
29 # WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
30 #是否开启web-jdbc监控 默认是false
31 spring.datasource.druid.web-stat.enabled=true
32 #是否开启session统计 默认false
33 spring.datasource.druid.web-stat.session-stat-enable=true
34 #设置session统计的最大值 默认是1000
35 spring.datasource.druid.web-stat.session-stat-max-count=1000
36 #是否开启单个监控url调用的sql列表 默认开启
37 spring.datasource.druid.web-stat.profile-enable=true
38 #过滤器url的映射规则
39 spring.datasource.druid.web-stat.url-patterns=/*
40 #过滤器url的排除规则
41 spring.datasource.druid.web-stat.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
42
43 # StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
44 #是否开启druid的数据统计界面 默认false
45 spring.datasource.druid.stat-view-servlet.enabled= true
46 #servlet映射规则,默认访问http:/**xxx/druid/
47 spring.datasource.druid.stat-view-servlet.url-mappings=/druid/*
48 #是否允许清空统计数据 默认false
49 spring.datasource.druid.stat-view-servlet.reset-enable= false
50 #设置登录名
51 spring.datasource.druid.stat-view-servlet.login-username= admin
52 #设置密码
53 spring.datasource.druid.stat-view-servlet.login-password= admin
54 #设置白名单
55 spring.datasource.druid.stat-view-servlet.allow= 127.0.0.1
56 #访问黑名单
57 #spring.datasource.druid.stat-view-servlet.deny= 192.168.32.139
3.创建配置类(上面如果全写了下面配置类也就不需要了)
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
/**
* Druid数据监控配置类,哪里配置了Druid数据库监控,哪里就需要添加这个类
* @author chy
*
*/
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean(destroyMethod="close", initMethod = "init")
public DataSource druid(){
return new DruidDataSource();
}
/**
* 配置监控服务器
**/
@Bean
// @WebInitParam(name="allow",value="192.168.246.1,127.0.0.1")// IP白名单 (没有配置或者为空,则允许所有访问)
// @WebInitParam(name="deny",value="192.168.16.111"),// IP黑名单 (存在共同时,deny优先于allow)
public ServletRegistrationBean<StatViewServlet> statViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<StatViewServlet>(
new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();
//设置白名单 (没有配置或者为空,则允许所有访问)
initParams.put("allow", "192.168.246.1,127.0.0.1,localhost");
//设置黑名单(存在共同时,deny优先于allow)
initParams.put("deny", "192.168.16.111");
// druid后台管理员用户
initParams.put("loginUsername","test");
initParams.put("loginPassword","1");
// 是否能够重置数据
initParams.put("resetEnable", "false");
bean.setInitParameters(initParams);
return bean;
}
/**
* 配置web监控的过滤器
**/
@Bean
public FilterRegistrationBean<WebStatFilter> webStatFilter(){
FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<WebStatFilter>( new WebStatFilter());
// 添加过滤规则
bean.addUrlPatterns("/*");
Map<String,String> initParams = new HashMap<>();
// 忽略过滤格式
initParams.put("exclusions","/static/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
bean.setInitParameters(initParams);
return bean;
}
}
4.开启Spring监控(配置切面)
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
/**
* 开启Druid数据库监控的Spring监控
* @author 曹海洋
*
*/
@Configuration
public class SpringDaoMethodAspect {
@Bean
public DruidStatInterceptor druidStatInterceptor() {
DruidStatInterceptor dsInterceptor = new DruidStatInterceptor();
return dsInterceptor;
}
@Bean
@Scope("prototype")
public JdkRegexpMethodPointcut druidStatPointcut() {
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern("ah.szxy.springcloud.mapper.*");
return pointcut;
}
@Bean
public DefaultPointcutAdvisor druidStatAdvisor(DruidStatInterceptor druidStatInterceptor, JdkRegexpMethodPointcut druidStatPointcut) {
DefaultPointcutAdvisor defaultPointAdvisor = new DefaultPointcutAdvisor();
defaultPointAdvisor.setPointcut(druidStatPointcut);
defaultPointAdvisor.setAdvice(druidStatInterceptor);
return defaultPointAdvisor;
}
}
5.访问改地址(需要有Web启动器的支持)
http://localhost:配置druid项目的端口号/druid/index
登录页(不需要自己创建,阿里为我们提供)
密码在Druid的数据监控的配置类中
首页
三. SpringBoot如何整合 Shrio?
1.添加坐标
<!-- Shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.配置类
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ah.szxy.backend.exam.system.shiro.UserRealm;
/**
* Shiro配置类
* @author chy
*
*/
@Configuration
public class ShiroConfig {
@Bean("hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
// 指定加密方式为MD5
credentialsMatcher.setHashAlgorithmName("MD5");
// 加密次数
credentialsMatcher.setHashIterations(1);
// credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
}
@Bean("userRealm")
public UserRealm userRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
UserRealm userRealm = new UserRealm();
userRealm.setCredentialsMatcher(matcher);
return userRealm;
}
/**
* 注入 securityManager
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(HashedCredentialsMatcher hashedCredentialsMatcher) {
DefaultWebSecurityManager securityManager
= new DefaultWebSecurityManager();
// 关联realm.
securityManager.setRealm(userRealm(hashedCredentialsMatcher));
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置 SecurityManager
bean.setSecurityManager(securityManager);
// 设置登录跳转Url
bean.setLoginUrl("/login");
//bean.setLoginUrl("http://localhost:9999/backend_exam_system/login");//这里将登陆的url修改成网关的url了
bean.setSuccessUrl("/main");
// 设置未授权提示Url
bean.setUnauthorizedUrl("/unauthorized.jsp");
/**
* anon:匿名用户可访问 authc:认证用户可访问 user:使用rememberMe可访问 perms:对应权限可访问 role:对应角色权限可访问
**/
Map<String, String> filterMap = new LinkedHashMap<>();
// 对静态资源设置允许匿名访问
filterMap.put("/static/**", "anon");
filterMap.put("static/**", "anon");
filterMap.put("/genCaptcha", "anon");
filterMap.put("/login", "anon");
// 退出,会调用Subject的logout方法,此方法 会将session清空
filterMap.put("/logout", "logout");
// 剩余其他路径,必须认证通过才可以访问
filterMap.put("/**", "authc");
bean.setFilterChainDefinitionMap(filterMap);
return bean;
}
// @Bean
// public CookieRememberMeManager cookieRememberMeManager() {
// CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
// SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// simpleCookie.setMaxAge(259200000);
// cookieRememberMeManager.setCookie(simpleCookie);
// cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j5Y+R5aSn5ZOlAA=="));
// return cookieRememberMeManager;
// }
}
3.自定义身验证规则
package ah.szxy.backend.exam.system.shiro;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import ah.szxy.backend.exam.system.service.SysUserService;
import ah.szxy.exam.system.entity.SysUser;
import ah.szxy.exam.system.utils.Constants;
import ah.szxy.exam.system.utils.Encodes;
import lombok.Data;
/**
* 自定义UserRealm
*
* @author chy
*
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
SysUserService sysUserService;
/**
* 授权
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal();
String userType = shiroUser.getUserType();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if ("1".equals(userType)) {
info.addRole("admin");
} else if ("2".equals(userType)) {
info.addRole("teacher");
} else if ("3".equals(userType)) {
info.addRole("student");
}
return info;
}
/**
* 认证
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
String username = (String) usernamePasswordToken.getPrincipal();
SysUser userDB = sysUserService.findSysUserByLoginName(username);
// 未找到账号
if (userDB == null) {
throw new UnknownAccountException();
}
if (Boolean.TRUE.equals(userDB.getLocked())) {
throw new LockedAccountException(); // 帐号锁定
}
byte[] salt = Encodes.decodeHex(userDB.getSalt());
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
new ShiroUser(userDB.getId(), userDB.getLoginName(), userDB.getNickName(), userDB.getIcon(),
userDB.getUserType()),
userDB.getPassword(), // 密码
ByteSource.Util.bytes(salt), getName() // realm name
);
return authenticationInfo;
}
/**
* 设定Password校验的Hash算法与迭代次数.
*/
@PostConstruct
public void initCredentialsMatcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Constants.HASH_ALGORITHM);
matcher.setHashIterations(Constants.HASH_INTERATIONS);
setCredentialsMatcher(matcher);
}
/**
* 清理缓存权限
*/
public void clearCachedAuthorizationInfo() {
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
public void removeUserAuthorizationInfoCache(String username) {
SimplePrincipalCollection pc = new SimplePrincipalCollection();
pc.add(username, super.getName());
super.clearCachedAuthorizationInfo(pc);
}
/**
* 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true) //忽略值为空的情况,方便在redis中进行json格式的数据传送
public static class ShiroUser implements Serializable {
private static final long serialVersionUID = -1373760761780840081L;
public Integer id;
public String loginName;
public String nickName;
public String icon;
public String userType;
public ShiroUser(Integer id, String loginName, String nickName, String icon, String userType) {
this.id = id;
this.loginName = loginName;
this.nickName = nickName;
this.icon = icon;
this.userType = userType;
}
}
}
4.在controller的登陆方法使用
最重要的部分
//shiro
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password, Boolean.valueOf(rememberMe));
try {
subject.login(usernamePasswordToken);
if (subject.isAuthenticated()) {
map.put("url", "index");
}
session.setAttribute("user", sysUserService.findSysUserByLoginName(username));
}
全部代码
/**
* 处理登录请求
*/
@PostMapping("/login")
@ResponseBody
@Log("登录系统")
public RestResponse login(String password, String username, String rememberMe, HttpServletRequest request) {
//获取验证码
String code = request.getParameter("code");
if (StringUtils.isBlank(code)) {
return RestResponse.failure("验证码不能为空");
}//username="" username =null
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
return RestResponse.failure("用户名或者密码不能为空");
}
if (StringUtils.isBlank(rememberMe)) {
return RestResponse.failure("记住我不能为空");
}
//获取正确的验证码
HttpSession session = request.getSession();
if (session == null) {
return RestResponse.failure("session 超时");
}
String trueCode = (String) session.getAttribute(Constants.VALIDATE_CODE);
if (StringUtils.isBlank(trueCode)) {
return RestResponse.failure("获取验证码超时");
}
String errorMsg = "";
HashMap map = new HashMap();
//验证码不对
if (StringUtils.isBlank(code) || !trueCode.toLowerCase().equals(code.toLowerCase())) {
errorMsg = "验证码错误";
} else {
//shiro
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password, Boolean.valueOf(rememberMe));
try {
subject.login(usernamePasswordToken);
if (subject.isAuthenticated()) {
map.put("url", "index");
}
session.setAttribute("user", sysUserService.findSysUserByLoginName(username));
} catch (IncorrectCredentialsException e) {
errorMsg = "登录密码错误.";
} catch (ExcessiveAttemptsException e) {
errorMsg = "登录失败次数过多";
} catch (LockedAccountException e) {
errorMsg = "帐号已被锁定.";
} catch (DisabledAccountException e) {
errorMsg = "帐号已被禁用.";
} catch (ExpiredCredentialsException e) {
errorMsg = "帐号已过期.";
} catch (UnknownAccountException e) {
errorMsg = "帐号不存在";
} catch (UnauthorizedException e) {
errorMsg = "您没有得到相应的授权!";
}
}
if (StringUtils.isBlank(errorMsg)) {
return RestResponse.success("登录成功").setData(map);
} else {
return RestResponse.failure(errorMsg);
}
}
5.在html页面通过使用shiro:hasRole
标签进行角色判断
<shiro:hasRole name="student">
<dd class="layui-this" data-menu="contentManagement">
<a href="javascript:;"><i class="layui-icon" data-icon=""></i>
<cite>在线考试</cite>
</a>
</dd>
</shiro:hasRole>
<shiro:hasAnyRoles name="admin,teacher">
<dd data-menu="memberCenter">
<a href="javascript:;">
<i class="seraph icon-icon10" data-icon="icon-icon10"></i>
<cite>考试管理</cite>
</a>
</dd>
</shiro:hasAnyRoles>
<shiro:hasRole name="admin">
<dd data-menu="systemeSttings">
<a href="javascript:;"><i class="layui-icon" data-icon=""></i>
<cite>系统管理</cite>
</a>
</dd>
</shiro:hasRole>
</dl>
</li>
</ul>
<ul class="layui-nav topLevelMenus" pc>
<shiro:hasRole name="student">
<li class="layui-nav-item layui-this" data-menu="contentManagement">
<a href="javascript:;"><i class="layui-icon" data-icon=""></i>
<cite>在线考试</cite>
</a>
</li>
</shiro:hasRole>
<shiro:hasAnyRoles name="admin,teacher">
<li class="layui-nav-item" data-menu="memberCenter" pc>
<a href="javascript:;">
<i class="seraph icon-icon10" data-icon="icon-icon10"></i>
<cite>考试管理</cite>
</a>
</li>
</shiro:hasAnyRoles>
<shiro:hasRole name="admin">
<li class="layui-nav-item" data-menu="systemeSttings" pc>
<a href="javascript:;">
<i class="layui-icon" data-icon=""></i>
<cite>系统设置</cite>
</a>
</li>
</shiro:hasRole>
4.如何快速为实体类添加get.set等一系列方法?
1.添加坐标
<!--lombok,使用@Data注解所需要的jar包 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.在实体类上添加注解
import lombok.Data;
@Data
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private Long phone;
private String deptartment;
}
注解描述
百度翻译
转载:https://blog.csdn.net/qq_43371556/article/details/102526787
查看评论