[TOC]
## 1. 创建SpringBoot项目(整合mybatis)
### 1.1 新建springboot项目
> 1. 新建项目【File】>【New】>【Project】
![](https://box.kancloud.cn/1def4fc75d9ef8e4ecb96d7a380fd8df_704x662.png)
> 2. 选择【Spring Initializer】> 【next】
![](https://box.kancloud.cn/8414606ffe29fe2ae510011fd42b9dec_828x812.png)
> 3. 填写项目信息
![](https://box.kancloud.cn/27bc173606dfd1b3758c615908565382_828x812.png)
> 4. 加入web,mybatis,mysql 【NEXT】
![](https://box.kancloud.cn/f78d7105f87218a75404887fcef3512d_826x796.png)
![](https://box.kancloud.cn/dec9ecfc7864d0a28cebbf8c372d0c5e_828x812.png)
> 5. finish
>
这样intellij会自动为我们引入web、mybatis所需要的依赖
### 1.2 根据表自动生成model,mapper(可选)
使用mybatis-generator根据数据库表,自动生成model和mapper代码
#### 1.2.1 修改pom.xml文件,指定生成代码的保存位置
> 记得新建:
> net.aexit.infrastructure.common.mapper
> net.aexit.infrastructure.common.model
> net.aexit.infrastructure.common.mapper
~~~
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- MyBatis Generator -->
<!-- Java接口和实体类,自动生成的存放位置 -->
<targetJavaProject>${basedir}/src/main/java</targetJavaProject>
<targetXmlProject>${basedir}/src/main/java</targetXmlProject>
<targetMapperPackage>net.aexit.infrastructure.common.mapper</targetMapperPackage>
<targetModelPackage>net.aexit.infrastructure.common.model</targetModelPackage>
<targetXMLPackage>net.aexit.infrastructure.common.mapper</targetXMLPackage>
</properties>
~~~
#### 1.2.2 建立文件夹generator,放入jar文件
![](https://box.kancloud.cn/083f58076397ca5d256c55170c4ba0b8_456x113.png)
jar链接:https://pan.baidu.com/s/1qZnlxoS 密码:fcey
#### 1.2.3 maven配置pom.xml书写
mybatis-generator-maven-plugin
~~~
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>com.xxg</groupId>
<artifactId>mybatis-generator-plugin</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/generator/mybatis-generator-plugin-1.0.0.jar</systemPath>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<filtering>false</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
</build>
~~~
#### 1.2.4 在generator文件夹下编写generatorConfig.xml文件,固定格式
~~~
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--此文件用于从数据库表结构,自动生成model,自动生成基础CURD的mapper代码 mvn mybatis-generator:generate-->
<!--<properties resource="./generator/generatorConfig.properties"/>-->
<!-- 数据库驱动包位置,使用maven的方法,这个就不用了 -->
<context id="MYSQLTables" targetRuntime="MyBatis3" defaultModelType="flat">
<!-- 生成的Java文件的编码 -->
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 格式化java代码 -->
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
<!-- 格式化XML代码 -->
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
<plugin type="com.xxg.mybatis.plugins.MySQLLimitPlugin"></plugin>
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 数据库链接URL、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://192.168.x.xx:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true"
userId="test"
password="123456">
</jdbcConnection>
<javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}"/>
<sqlMapGenerator targetPackage="${targetXMLPackage}" targetProject="${targetXmlProject}"/>
<javaClientGenerator targetPackage="${targetMapperPackage}" targetProject="${targetJavaProject}" type="XMLMAPPER" />
<!-- mvn mybatis-generator:generate -->
<table tableName="sys_user"/>
</context>
</generatorConfiguration>
~~~
#### 1.2.5 命令行生成代码
> 在pom.xml的同级目录执行
~~~
mvn mybatis-generator:generate
~~~
#### 1.2.6 查看生成结果
可以看到自动生成了四个文件
> 1. SysUserMapper.java
> 2. SysUserMapper.xml
> 3. SysUser的实体类
> 4. SysUserExample,单表复杂数据库操作模板
有了以上的代码,针对单表的操作接近100%,不用写SQL!具体如何用好这四个类,后文详细讲解!
注意:一旦数据库表结构发生变化,需要重新生成4个文件!请先删除xml,如:SysUserMapper.xml ,因为追加不覆盖导致报错,
**会根据驼峰规则生成对象 **
role_id字段对应roleId属性;
role_name对应roleName;
**类依然是首字母大写**
![](https://box.kancloud.cn/0f7609b832be1f53ebd8e994f810ae9d_1699x517.png)
#### 1.2.7 如何获取insert的自增key.
配置,自动生成的代码是没有useGeneratedKeys="true" keyProperty="id"这个配置的,需要加上.
~~~
<insert id="insert" parameterType="net.aexit.infrastructure.common.model.SysUser" useGeneratedKeys="true" keyProperty="id">
insert into sys_user (id, user_id, user_name,
password, salt, org_id,
phone, address, sex,
email, remarks, create_date,
head_image, status)
values (#{id,jdbcType=INTEGER}, #{userId,jdbcType=VARCHAR}, #{userName,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR}, #{orgId,jdbcType=VARCHAR},
#{phone,jdbcType=VARCHAR}, #{address,jdbcType=VARCHAR}, #{sex,jdbcType=TINYINT},
#{email,jdbcType=VARCHAR}, #{remarks,jdbcType=VARCHAR}, #{createDate,jdbcType=TIMESTAMP},
#{headImage,jdbcType=VARCHAR}, #{status,jdbcType=TINYINT})
</insert>
~~~
• 获取
~~~
this.sysUserMapper.insert(sysUser);
return sysUser.getId();
~~~
这样就生成了model,和mapper
![](https://box.kancloud.cn/dd9e23782b9439a925e13bc7ef3cc3c6_638x333.png)
### 1.3 测试mybatis
1. 设置扫描
~~~
@SpringBootApplication
@ComponentScan(basePackages = {"com.aixin"})
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
~~~
2. 扫描mapper
~~~
package com.aixin.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
/**
* Created by dailin on 2018/1/9.
*/
@Configuration
@MapperScan("com.**.mapper")
public class MybatisConfig {
}
~~~
3. mapper添加方法
~~~
Userinfo findByUsername(String userName);
~~~
4. 配置xml添加SQL
~~~
<select id="findByUsername" parameterType="string" resultMap="BaseResultMap">
SELECT *
FROM UserInfo
WHERE username=#{userName}
</select>
~~~
5. service
接口
~~~
package com.tuna.service;
import com.tuna.model.Userinfo;
public interface UserInfoService {
/**通过username查找用户信息;*/
public Userinfo findByUsername(String username);
}
~~~
实现类
~~~
package com.tuna.service;
import javax.annotation.Resource;
import com.tuna.mapper.UserinfoMapper;
import com.tuna.model.Userinfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserInfoServiceImpl implements UserInfoService{
@Autowired
private UserinfoMapper userinfoMapper;
@Override
public Userinfo findByUsername(String username) {
System.out.println("UserInfoServiceImpl.findByUsername()");
return userinfoMapper.findByUsername(username);
}
}
~~~
6. controller
~~~
package com.tuna.controller;
import com.tuna.model.Userinfo;
import com.tuna.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.websocket.server.PathParam;
/**
* Created by dailin on 2018/1/9.
*/
@RestController
public class Hello {
@Autowired
private UserInfoService userInfoService;
@RequestMapping("/hello")
public Userinfo sayHello(){
Userinfo userInfo = userInfoService.findByUsername("admin");
return userInfo;
}
}
~~~
7. application.yml 配置
~~~
server:
port: 8090
address: 0.0.0.0
session:
timeout: 28800
################################################# 数据库访问配置
# 主数据源,默认的
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.56.130:3306/shiro?useUnicode=true&characterEncoding=utf8&autoReconnect=true
username: root
password: tuna
mybatis-plus:
configuration:
mapUnderscoreToCamelCase: true
~~~
8. 结果
![](https://box.kancloud.cn/7e859e48f575b306c8a7c55407ac0531_841x391.png)
## 2. 整合实例
上面创建项目时,自动完成了mybatis的整合
### 2.1 集成druid
1.添加maven依赖
~~~
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.2</version>
</dependency>
~~~
2. 配置数据源application.yml
数据库访问配置
~~~
# 主数据源,默认的
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.2.21:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true
username: test
password: 123456
druid:
initialSize: 2
minIdle: 2
maxActive: 30
WebStatFilter:
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
StatViewServlet:
loginUsername: aexit
loginPassword: aexit
~~~
3.查看监控,输入用户名密码,上文
访问:http://localhost:20001/druid/
![](https://box.kancloud.cn/2b37d39866e2681c8fe8bafcac65b6e2_495x285.png)
### 2.2 整合beetl
1. 引入maven
~~~
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>2.7.21</version>
</dependency>
~~~
* beetl提供了starter的方式集成springboot,但是经过试验,和druid有冲突!因为beetl-starter不但集成了模板,还集成了beetlSQL,和druid数据库连接池发生冲突!
* 所以不引入带starter的maven包!
2. 配置beetl基础信息
~~~
package com.aixin.tuna.webtest.config;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.beetl.ext.spring.BeetlSpringViewResolver;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class BeetlTplConfig extends BeetlGroupUtilConfiguration {
@Bean(initMethod = "init", name = "beetlConfig")
public BeetlGroupUtilConfiguration getBeetlGroupUtilConfiguration() {
BeetlGroupUtilConfiguration beetlGroupUtilConfiguration = new BeetlGroupUtilConfiguration();
ClasspathResourceLoader classpathResourceLoader = new ClasspathResourceLoader();
beetlGroupUtilConfiguration.setResourceLoader(classpathResourceLoader);
Properties beetlConfigProperties = new Properties();
//是否检测文件变化,开发用true合适,但线上要改为false
beetlConfigProperties.setProperty("RESOURCE.autoCheck","true");
//自定义标签文件Root目录和后缀
beetlConfigProperties.setProperty("RESOURCE.tagRoot","templates/tags");
beetlConfigProperties.setProperty("RESOURCE.tagSuffix","tag");
beetlGroupUtilConfiguration.setConfigProperties(beetlConfigProperties);
return beetlGroupUtilConfiguration;
}
@Bean(name = "beetlViewResolver")
public BeetlSpringViewResolver getBeetlSpringViewResolver(@Qualifier("beetlConfig") BeetlGroupUtilConfiguration beetlGroupUtilConfiguration) {
BeetlSpringViewResolver beetlSpringViewResolver = new BeetlSpringViewResolver();
beetlSpringViewResolver.setPrefix("/templates/");
beetlSpringViewResolver.setSuffix(".html");
beetlSpringViewResolver.setContentType("text/html;charset=UTF-8");
beetlSpringViewResolver.setOrder(0);
beetlSpringViewResolver.setConfig(beetlGroupUtilConfiguration);
return beetlSpringViewResolver;
}
@Override
public void initOther() {
// groupTemplate.registerFunctionPackage("shiro", new ShiroKit());
// groupTemplate.registerFunctionPackage("tool", new ToolUtil());
}
}
~~~
例子
~~~
控制层
@Controller
public class LoginController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("name", "代林");
return "login";
}
}
~~~
显示层,放在resources/templates目录下面的login.html
~~~
<html lang="en">
<head>
<title>beetl servlet</title>
</head>
<body>
这是${name}的第一个beetl例子
</body>
</html>
~~~
访问
![](https://box.kancloud.cn/3a49a56daaf18561dfdbbd9a122b1a1e_1174x187.png)
### 2.3 整合shrio
#### 2.3.1 引入shrio依赖
<shiro.version>1.4.0</shiro.version>
~~~
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
~~~
#### 2.3.2 原理讲解
> ShiroConfiguration.java:
> shiro启动时候的初始化工作,比如哪些是需要认证,哪些不需要认证;缓存配置设置;shiro权限数据在页面展示时整合需要的模板套件配置,等等。
> ShiroRealm.java:
> shiro权限认证的具体实现代码,因为shiro本身只提供拦截路由,而具体如何数据源则由用户自己提供,不同的项目不同的要求,要不要加缓存登陆验证次数,要不要密码加密设置其他具体方式,这些都由用户自己决定,而shiro只提供给用户权限验证的格式接口,通过用户提供的数据源shrio判断要不要给具体用户授权请求路径的判断。
> ShiroRealm 涉及到以下点:
> principal:
> 主体,就是登陆的当前用户类型的数据实体
> credentials:
> 凭证,用户的密码,具体加密方式用户自己实现,什么都不做就是原文
> Roles:
> 用户拥有的角色标识(角色名称,admin,account,customer_service),字符串格式列表:用户拥有多个角色的可能
> Permissions:
> 用户拥有的权限标识(每个权限唯一标识,比如主键或者权限唯一标识编码),字符串格式列表:用户拥有多个权限的可能
#### 2.3.3 ShrioRealm
1. 用户登陆信息及权限配置
~~~
@Component("aexitShrioRealm")
public class AexitShrioRealm extends AuthorizingRealm {
@Resource
UserService userService;
@Resource
RoleService roleService;
@Resource
MenuService menuService;
/**
* 配置用户权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
}
String userId = (String) getAvailablePrincipal(principals);
List<String> roleList = roleService.getRoleIdsByUserId(userId);
//用户角色获取用户功能id
Set<String> roleSet = new HashSet<>(); //角色集合
Set<String> menuSet = new HashSet<>(); //菜单集合
List<String> menus;
for(String roleId : roleList){
roleSet.add(roleId);
menus = menuService.getMenuidsByRoleId(roleId);
Collections.addAll(menuSet,menus.toArray(new String[menus.size()]));
}
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(roleSet);
authorizationInfo.setStringPermissions(menuSet);
return authorizationInfo;
}
/**
* 配置登录认证信息
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String userId = token.getUsername();
if (userId == null) {
throw new AccountException("Null usernames are not allowed by this realm.");
}
//查出是否有此用户
SysUser curUser = userService.getByUserId(userId);
if(curUser == null)
throw new AccountException("account error:one user name must have one and only one user! ");
//密码加密
String password = ShiroKit.md5(curUser.getPassword(),curUser.getSalt());
return new SimpleAuthenticationInfo(userId, password, getName());
}
}
~~~
2. 用户登陆验证
~~~
/**
* 登陆验证
* @return
*/
@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public AjaxCommonObject login(@RequestParam(value="user_id",required = false) String userId,
@RequestParam(value="password",required = false) String password,
@RequestParam(value="user_validate_code",required = false) String userValidateCode,
HttpSession session) {
AjaxCommonObject ajaxCommonObject = new AjaxCommonObject();
try {
if (!userValidateCode.equals(session.getAttribute(Constants.KAPTCHA_SESSION_KEY))) {
throw new BizCommonException(400,"请输入正确的验证码!");
}
SysUser user = userService.getByUserId(userId.trim());
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(
userId,
ShiroKit.md5(password,user.getSalt()));
subject.login(token);
//登陆成功之后
session.setAttribute(AuthConstants.CURRENT_USER, user);
session.setAttribute(AuthConstants.DICTIONRYS,
sysDictionaryMapper.selectByExample(new SysDictionaryExample()));//数据字典
} catch (BizCommonException e) {
return new AjaxCommonObject(new BizCommonException(400,"请输入正确的用户名和密码!"));
}
return ajaxCommonObject;
}
~~~
3. shiro生命周期的管理配置
~~~
/**
* shiro生命周期配置项
* Created by hanxt on 2017/12/18.
*/
@Configuration
public class ShiroConfiguration {
@Resource
SysMenuExtMapper sysMenuExtMapper;
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean(name = "shiroRealm")
@DependsOn("lifecycleBeanPostProcessor")
public AexitShrioRealm shiroRealm() {
AexitShrioRealm realm = new AexitShrioRealm();
return realm;
}
@Bean(name = "ehCacheManager")
@DependsOn("lifecycleBeanPostProcessor")
public EhCacheManager ehCacheManager() {
EhCacheManager ehCacheManager = new EhCacheManager();
return ehCacheManager;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setCacheManager(ehCacheManager());//用户授权/认证信息Cache, 采用EhCache 缓存
return securityManager;
}
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionManager = new LinkedHashMap<>();
filterChainDefinitionManager.put("/druid/**", "anon");
filterChainDefinitionManager.put("/static/**", "anon");//静态资源不拦截
filterChainDefinitionManager.put("/login", "anon");//anon 可以理解为不拦截
filterChainDefinitionManager.put("/logout", "anon");//anon 可以理解为不拦截
filterChainDefinitionManager.put("/kaptcha", "anon");//anon 可以理解为不拦截
filterChainDefinitionManager.put("/", "anon");
filterChainDefinitionManager.put("/**", "authc,myperm");//authc未登录拦截 myperm 菜单url权限拦截
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);
shiroFilterFactoryBean.setLoginUrl("/");
//shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.setUnauthorizedUrl("/");
URLPermissionsFilter urlPermissionsFilter = new URLPermissionsFilter();
Map<String,Filter> filtermap = new HashMap<>();
filtermap.put("myperm",urlPermissionsFilter);shiroFilterFactoryBean.setFilters(filtermap);
return shiroFilterFactoryBean;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(securityManager);
return aasa;
}
//thymeleaf模板引擎和shiro整合时使用
/*@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}*/
}
~~~
#### 2.3.4 用户菜单url访问权限拦截
> 问题:当用户登录系统后,如果当前用户角色没有某些菜单访问权限,但是该用户知道菜单的url路径,其通过浏览器直接输入路径是可以访问的!
~~~
解决方法:
在我们配置shiro生命周期配置项时,我们做了两步操作
1:通过AexitShrioRealm将用户角色对应的菜单权限信息交给Shrio管理
2:配置拦截器
~~~
其实:还可以利用shiro标签和注解
![](https://box.kancloud.cn/17b5a00511ea5464f50857b2770ec291_984x776.png)
![](https://box.kancloud.cn/503ca4706d3fecb1bd698a6a32f67a31_1037x847.png)
> 然后我们通过URLPermissionsFilter 类来判断该请求是否是菜单请求,如果是菜单请求我们调用shiro为我们提供的isAccessAllowed(),
> 该方法会通过我们之前交给Shrio的用户角色对应的菜单权限信息来判断此次请求是否是该用户角色范围之内的请求,如果是可以请求,不是不可以访问。
**通过注解**
~~~
@RequestMapping("/listall")
@ResponseBody
@RequiresPermissions("userInfo:view")
public List<Userinfo> list(){
List<Userinfo> members = userInfoService.getMembers();
return members;
}
~~~
~~~
/**
* 自定义shiro的URL拦截器
* 拦截目标为菜单url,根据AexitShrioRealm配置的权限决定用户有没有权限访问菜单
* 注意:这里不做数据层面的请求限制
*/
public class URLPermissionsFilter extends PermissionsAuthorizationFilter {
/**
* @param mappedValue 指的是在声明url时指定的权限字符串,
* 如/User/create.do=perms[User:create].我们要动态产生这个权限字符串,所以这个配置对我们没用
*/
@SuppressWarnings("unchecked")
public boolean isAccessAllowed(ServletRequest request,
ServletResponse response, Object mappedValue) throws IOException {
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getServletPath();
//用户在登陆时把系统所有的菜单项目保存到list里面
List<SysMenu> sysMenus = (List<SysMenu>)((HttpServletRequest) request).getSession().getAttribute(AuthConstants.MENUS);
if(sysMenus != null){
for(SysMenu menu : sysMenus){
if(path.equals(menu.getUrl())){
//根据AexitShrioRealm配置的权限决定用户有没有权限访问菜单
return super.isAccessAllowed(request, response, buildPermissions(request));
}
}
}
//不是菜单的,不做数据层面的请求限制
return true;
}
/**
* 根据请求URL产生权限字符串(如:/menu),这里只产生,而比对的事交给Realm
*/
protected String[] buildPermissions(ServletRequest request) {
String[] perms = new String[1];
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getServletPath();
perms[0] = path;//path直接作为权限字符串
return perms;
}
}
~~~
### 2.4 SpringBoot集成kaptcha验证码
1. 添加maven依赖
~~~
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
~~~
2. 验证码配置文件
因为kaptcha的配置不符合yaml的规范,所以只能采用properties,新建kaptcha.properties
~~~
kaptcha.border=yes
kaptcha.border.color=105,179,90
kaptcha.textproducer.font.color=blue
kaptcha.image.width=100
kaptcha.image.height=35
kaptcha.session.key=code
kaptcha.textproducer.char.length=4
kaptcha.textproducer.font.names=宋体,楷体,微软雅黑
~~~
3. 新建配置文件CaptchaConfig 读取配置
~~~
@Component
@PropertySource(value = {"classpath:kaptcha.properties"})
public class CaptchaConfig {
@Value("${kaptcha.border}")
private String border;
@Value("${kaptcha.border.color}")
private String borderColor;
@Value("${kaptcha.textproducer.font.color}")
private String fontColor;
@Value("${kaptcha.image.width}")
private String imageWidth;
@Value("${kaptcha.image.height}")
private String imageHeight;
@Value("${kaptcha.session.key}")
private String sessionKey;
@Value("${kaptcha.textproducer.char.length}")
private String charLength;
@Value("${kaptcha.textproducer.font.names}")
private String fontNames;
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty("kaptcha.border", border);
properties.setProperty("kaptcha.border.color", borderColor);
properties.setProperty("kaptcha.textproducer.font.color", fontColor);
properties.setProperty("kaptcha.image.width", imageWidth);
properties.setProperty("kaptcha.image.height", imageHeight);
properties.setProperty("kaptcha.session.key", sessionKey);
properties.setProperty("kaptcha.textproducer.char.length", charLength);
properties.setProperty("kaptcha.textproducer.font.names", fontNames);
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
~~~
4. 生成验证码
~~~
@Resource
DefaultKaptcha captchaProducer;
/**
* 获取验证码
*/
@RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
public void kaptcha(HttpSession session,HttpServletResponse response) throws Exception {
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
response.setContentType("image/jpeg");
String capText = captchaProducer.createText();
//TODO 如果是前后台分离或分布式部署,这里需要使用SpringSession放到redis里面
//将验证码存到session
session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
// create the image with the text
BufferedImage bi = captchaProducer.createImage(capText);
ServletOutputStream out = response.getOutputStream();
// write the data out
ImageIO.write(bi, "jpg", out);
try {
out.flush();
} finally {
out.close();
}
}
~~~
5. 模拟访问界面
~~~
<img src="${ctxPath}/kaptcha" id="kaptcha" width="100%" height="100%"/>
<script>
$(function(){
$("#kaptcha").on('click',function(){
$("#kaptcha").attr('src', '${ctxPath}/kaptcha?' + Math.floor(Math.random()*100) ).fadeIn();
});
});
</script>
~~~
注意:页面需要引用js,css,需要配置静态文件目录
~~~
spring:
mvc:
static-path-pattern: /static/**
~~~
### 2.5 整合mybatis-plus分页
1. 引入pom依赖
~~~
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<shiro.version>1.4.0</shiro.version>
<mybatisplus-spring-boot-starter.version>1.0.4</mybatisplus-spring-boot-starter.version>
<mybatisplus.version>2.1-gamma</mybatisplus.version>
</properties
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<version>${mybatisplus-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
~~~
2. 配置分页
~~~
package com.aixin.tuna.weblearn.weblearn.config;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan(basePackages = {"com.aixin.tuna.**.mapper"})
public class MybatisPlusConfig {
/**
* mybatis-plus分页插件<br>
* 文档:http://mp.baomidou.com<br>
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
~~~
3. controller
~~~
@GetMapping(value = "/list")
@ResponseBody
public List<FederatedCompany> list(@RequestParam(required = false) Integer pageIndex,
@RequestParam(required = false) Integer pageSize) {
Page<FederatedCompany> federatedCompanyPage;
if (pageIndex !=null && pageSize !=null) {
federatedCompanyPage = new Page<>(pageIndex,pageSize); //创建page对象,传入当前页和每页显示条目数
} else {
federatedCompanyPage = new Page<>(1,Integer.MAX_VALUE);
}
return federatedCompanyService.getCompanyList(federatedCompanyPage);
}
~~~
4. service
~~~
@Resource
FederatedCompanyMapper federatedCompanyMapper;
public List<FederatedCompany> getCompanyList(Page<FederatedCompany> page) {
return federatedCompanyMapper.list(page);
}
~~~
5. mapper接口
接口接收page对象,自动分页
~~~
List<FederatedCompany> list(Page<FederatedCompany> page);
~~~
6. mapper.xml
~~~
<select id="list" resultType="com.aixin.tuna.weblearn.weblearn.enterprise.model.FederatedCompany">
select *
from federated_company
</select>
~~~
![](https://box.kancloud.cn/6a07adca5b67f260a45da054f25822da_863x389.png)
- Docker
- 什么是docker
- Docker安装、组件启动
- docker网络
- docker命令
- docker swarm
- dockerfile
- mesos
- 运维
- Linux
- Linux基础
- Linux常用命令_1
- Linux常用命令_2
- ip命令
- 什么是Linux
- SELinux
- Linux GCC编译警告:Clock skew detected. 错误解决办法
- 文件描述符
- find
- 资源统计
- LVM
- Linux相关配置
- 服务自启动
- 服务器安全
- 字符集
- shell脚本
- shell命令
- 实用脚本
- shell 数组
- 循环与判断
- 系统级别进程开启和停止
- 函数
- java调用shell脚本
- 发送邮件
- Linux网络配置
- Ubuntu
- Ubuntu发送邮件
- 更换apt-get源
- centos
- 防火墙
- 虚拟机下配置网络
- yum重新安装
- 安装mysql5.7
- 配置本地yum源
- 安装telnet
- 忘记root密码
- rsync+ crontab
- Zabbix
- Zabbix监控
- Zabbix安装
- 自动报警
- 自动发现主机
- 监控MySQL
- 安装PHP常见错误
- 基于nginx安装zabbix
- 监控Tomcat
- 监控redis
- web监控
- 监控进程和端口号
- zabbix自定义监控
- 触发器函数
- zabbix监控mysql主从同步状态
- Jenkins
- 安装Jenkins
- jenkins+svn+maven
- jenkins执行shell脚本
- 参数化构建
- maven区分环境打包
- jenkins使用注意事项
- nginx
- nginx认证功能
- ubuntu下编译安装Nginx
- 编译安装
- Nginx搭建本地yum源
- 文件共享
- Haproxy
- 初识Haproxy
- haproxy安装
- haproxy配置
- virtualbox
- virtualbox 复制新的虚拟机
- ubuntu下vitrualbox安装redhat
- centos配置双网卡
- 配置存储
- Windows
- Windows安装curl
- VMware vSphere
- 磁盘管理
- 增加磁盘
- gitlab
- 安装
- tomcat
- Squid
- bigdata
- FastDFS
- FastFDS基础
- FastFDS安装及简单实用
- api介绍
- 数据存储
- FastDFS防盗链
- python脚本
- ELK
- logstash
- 安装使用
- kibana
- 安准配置
- elasticsearch
- elasticsearch基础_1
- elasticsearch基础_2
- 安装
- 操作
- java api
- 中文分词器
- term vector
- 并发控制
- 对text字段排序
- 倒排和正排索引
- 自定义分词器
- 自定义dynamic策略
- 进阶练习
- 共享锁和排它锁
- nested object
- 父子关系模型
- 高亮
- 搜索提示
- Redis
- redis部署
- redis基础
- redis运维
- redis-cluster的使用
- redis哨兵
- redis脚本备份还原
- rabbitMQ
- rabbitMQ安装使用
- rpc
- RocketMQ
- 架构概念
- 安装
- 实例
- 好文引用
- 知乎
- ACK
- postgresql
- 存储过程
- 编程语言
- 计算机网络
- 基础_01
- tcp/ip
- http转https
- Let's Encrypt免费ssl证书(基于haproxy负载)
- what's the http?
- 网关
- 网络IO
- http
- 无状态网络协议
- Python
- python基础
- 基础数据类型
- String
- List
- 遍历
- Python基础_01
- python基础_02
- python基础03
- python基础_04
- python基础_05
- 函数
- 网络编程
- 系统编程
- 类
- Python正则表达式
- pymysql
- java调用python脚本
- python操作fastdfs
- 模块导入和sys.path
- 编码
- 安装pip
- python进阶
- python之setup.py构建工具
- 模块动态导入
- 内置函数
- 内置变量
- path
- python模块
- 内置模块_01
- 内置模块_02
- log模块
- collections
- Twisted
- Twisted基础
- 异步编程初探与reactor模式
- yield-inlineCallbacks
- 系统编程
- 爬虫
- urllib
- xpath
- scrapy
- 爬虫基础
- 爬虫种类
- 入门基础
- Rules
- 反反爬虫策略
- 模拟登陆
- problem
- 分布式爬虫
- 快代理整站爬取
- 与es整合
- 爬取APP数据
- 爬虫部署
- collection for ban of web
- crawlstyle
- API
- 多次请求
- 向调度器发送请求
- 源码学习
- LinkExtractor源码分析
- 构建工具-setup.py
- selenium
- 基础01
- 与scrapy整合
- Django
- Django开发入门
- Django与MySQL
- java
- 设计模式
- 单例模式
- 工厂模式
- java基础
- java位移
- java反射
- base64
- java内部类
- java高级
- 多线程
- springmvc-restful
- pfx数字证书
- 生成二维码
- 项目中使用log4j
- 自定义注解
- java发送post请求
- Date时间操作
- spring
- 基础
- spring事务控制
- springMVC
- 注解
- 参数绑定
- springmvc+spring+mybatis+dubbo
- MVC模型
- SpringBoot
- java配置入门
- SpringBoot基础入门
- SpringBoot web
- 整合
- SpringBoot注解
- shiro权限控制
- CommandLineRunner
- mybatis
- 静态资源
- SSM整合
- Aware
- Spring API使用
- Aware接口
- mybatis
- 入门
- mybatis属性自动映射、扫描
- 问题
- @Param 注解在Mybatis中的使用 以及传递参数的三种方式
- mybatis-SQL
- 逆向生成dao、model层代码
- 反向工程中Example的使用
- 自增id回显
- SqlSessionDaoSupport
- invalid bound statement(not found)
- 脉络
- beetl
- beetl是什么
- 与SpringBoot整合
- shiro
- 什么是shiro
- springboot+shrio+mybatis
- 拦截url
- 枚举
- 图片操作
- restful
- java项目中日志处理
- JSON
- 文件工具类
- KeyTool生成证书
- 兼容性问题
- 开发规范
- 工具类开发规范
- 压缩图片
- 异常处理
- web
- JavaScript
- 基础语法
- 创建对象
- BOM
- window对象
- DOM
- 闭包
- form提交-文件上传
- td中内容过长
- 问题1
- js高级
- js文件操作
- 函数_01
- session
- jQuery
- 函数01
- data()
- siblings
- index()与eq()
- select2
- 动态样式
- bootstrap
- 表单验证
- 表格
- MUI
- HTML
- iframe
- label标签
- 规范编程
- layer
- sss
- 微信小程序
- 基础知识
- 实践
- 自定义组件
- 修改自定义组件的样式
- 基础概念
- appid
- 跳转
- 小程序发送ajax
- 微信小程序上下拉刷新
- if
- 工具
- idea
- Git
- maven
- svn
- Netty
- 基础概念
- Handler
- SimpleChannelInboundHandler 与 ChannelInboundHandler
- 网络编程
- 网络I/O
- database
- oracle
- 游标
- PLSQL Developer
- mysql
- MySQL基准测试
- mysql备份
- mysql主从不同步
- mysql安装
- mysql函数大全
- SQL语句
- 修改配置
- 关键字
- 主从搭建
- centos下用rpm包安装mysql
- 常用sql
- information_scheme数据库
- 值得学的博客
- mysql学习
- 运维
- mysql权限
- 配置信息
- 好文mark
- jsp
- jsp EL表达式
- C
- test