[TOC]
## 1. 創建SpringBoot項目(整合mybatis)
### 1.1 新建springboot項目
> 1. 新建項目【File】>【New】>【Project】

> 2. 選擇【Spring Initializer】> 【next】

> 3. 填寫項目信息

> 4. 加入web,mybatis,mysql 【NEXT】


> 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文件

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;
**類依然是首字母大寫**

#### 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

### 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. 結果

## 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/

### 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>
~~~
訪問

### 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標簽和注解


> 然后我們通過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>
~~~

- 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