技术标签: shiro springboot
转载自github,地址https://github.com/Heeexy/SpringBoot-Shiro-Vue
目录结构:
application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: root
password: root
mybatis:
mapperLocations: classpath:/mapper/*.xml
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<contextName>heeexy</contextName>
<!--定义日志文件的存储地址 -->
<property name="LOG_HOME" value="logs"/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<!--encoder 默认配置为PatternLayoutEncoder-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<appender name="RollingFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<!-- 可让每天产生一个日志文件,最多 180 个,自动回滚 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM,aux}/heeexy-%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- keep 180 days' worth of history capped at 50GB total size -->
<maxHistory>180</maxHistory>
<totalSizeCap>40GB</totalSizeCap>
</rollingPolicy>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%file:%line][%thread] - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<appender name="AsyncRollingFile" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="RollingFile"/>
<includeCallerData>true</includeCallerData>
</appender>
<!-- 输出到控制台和文件,可定义更多的 Appender -->
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="AsyncRollingFile"/>
</root>
<!-- 下面配置一些第三方包的日志过滤级别,用于避免刷屏 -->
<logger name="org.mybatis" level="INFO"/>
<logger name="org.springframework" level="WARN"/>
<logger name="org.apache" level="WARN"/>
<!--如果需要打印SQL,可以把下面的级别设置为DEBUG -->
<logger name="com.heeexy.example.dao" level="DEBUG"/>
</configuration>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.heeexy</groupId>
<artifactId>example</artifactId>
<version>1.1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>permissionExample</name>
<description>权限后端</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>
exception.CommonJsonException
package com.heeexy.example.config.exception;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.util.CommonUtil;
import com.heeexy.example.util.constants.ErrorEnum;
/**
* @author: hxy
* @description: 本系统使用的自定义错误类
* 比如在校验参数时,如果不符合要求,可以抛出此错误类
* 拦截器可以统一拦截此错误,将其中json返回给前端
* @date: 2017/10/24 10:29
*/
public class CommonJsonException extends RuntimeException {
private JSONObject resultJson;
/**
* 调用时可以在任何代码处直接throws这个Exception,
* 都会统一被拦截,并封装好json返回给前台
*
* @param errorEnum 以错误的ErrorEnum做参数
*/
public CommonJsonException(ErrorEnum errorEnum) {
this.resultJson = CommonUtil.errorJson(errorEnum);
}
public CommonJsonException(JSONObject resultJson) {
this.resultJson = resultJson;
}
public JSONObject getResultJson() {
return resultJson;
}
}
exception.GlobalExceptionHandler
package com.heeexy.example.config.exception;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.util.CommonUtil;
import com.heeexy.example.util.constants.ErrorEnum;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* @author: hxy
* @description: 统一异常拦截
* @date: 2017/10/24 10:31
*/
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass().getName());
@ExceptionHandler(value = Exception.class)
public JSONObject defaultErrorHandler(HttpServletRequest req, Exception e) {
String errorPosition = "";
//如果错误堆栈信息存在
if (e.getStackTrace().length > 0) {
StackTraceElement element = e.getStackTrace()[0];
String fileName = element.getFileName() == null ? "未找到错误文件" : element.getFileName();
int lineNumber = element.getLineNumber();
errorPosition = fileName + ":" + lineNumber;
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", ErrorEnum.E_400.getErrorCode());
jsonObject.put("msg", ErrorEnum.E_400.getErrorMsg());
JSONObject errorObject = new JSONObject();
errorObject.put("errorLocation", e.toString() + " 错误位置:" + errorPosition);
jsonObject.put("info", errorObject);
logger.error("异常", e);
return jsonObject;
}
/**
* GET/POST请求方法错误的拦截器
* 因为开发时可能比较常见,而且发生在进入controller之前,上面的拦截器拦截不到这个错误
* 所以定义了这个拦截器
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public JSONObject httpRequestMethodHandler() {
return CommonUtil.errorJson(ErrorEnum.E_500);
}
/**
* 本系统自定义错误的拦截器
* 拦截到此错误之后,就返回这个类里面的json给前端
* 常见使用场景是参数校验失败,抛出此错,返回错误信息给前端
*/
@ExceptionHandler(CommonJsonException.class)
public JSONObject commonJsonExceptionHandler(CommonJsonException commonJsonException) {
return commonJsonException.getResultJson();
}
/**
* 权限不足报错拦截
*/
@ExceptionHandler(UnauthorizedException.class)
public JSONObject unauthorizedExceptionHandler() {
return CommonUtil.errorJson(ErrorEnum.E_502);
}
/**
* 未登录报错拦截
* 在请求需要权限的接口,而连登录都还没登录的时候,会报此错
*/
@ExceptionHandler(UnauthenticatedException.class)
public JSONObject unauthenticatedException() {
return CommonUtil.errorJson(ErrorEnum.E_20011);
}
}
exception.MainsiteErrorController
package com.heeexy.example.config.exception;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.util.CommonUtil;
import com.heeexy.example.util.constants.ErrorEnum;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author: hxy
* @description: 系统错误拦截, 主要是针对404的错误
* @date: 2017/10/24 10:31
*/
@Controller
public class MainsiteErrorController implements ErrorController {
private static final String ERROR_PATH = "/error";
/**
* 主要是登陆后的各种错误路径 404页面改为返回此json
* 未登录的情况下,大部分接口都已经被shiro拦截,返回让用户登录了
*
* @return 501的错误信息json
*/
@RequestMapping(value = ERROR_PATH)
@ResponseBody
public JSONObject handleError() {
return CommonUtil.errorJson(ErrorEnum.E_501);
}
@Override
public String getErrorPath() {
return ERROR_PATH;
}
}
shiro.AjaxPermissionsAuthorizationFilter
package com.heeexy.example.config.shiro;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.util.constants.ErrorEnum;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @author: hxy
* @description: 对没有登录的请求进行拦截, 全部返回json信息. 覆盖掉shiro原本的跳转login.jsp的拦截方式
* @date: 2017/10/24 10:11
*/
public class AjaxPermissionsAuthorizationFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", ErrorEnum.E_20011.getErrorCode());
jsonObject.put("msg", ErrorEnum.E_20011.getErrorMsg());
PrintWriter out = null;
HttpServletResponse res = (HttpServletResponse) response;
try {
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json");
out = response.getWriter();
out.println(jsonObject);
} catch (Exception e) {
} finally {
if (null != out) {
out.flush();
out.close();
}
}
return false;
}
@Bean
public FilterRegistrationBean registration(AjaxPermissionsAuthorizationFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
}
shiro.ShiroConfiguration
package com.heeexy.example.config.shiro;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
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.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author: hxy
* @description: shiro配置类
* @date: 2017/10/24 10:10
*/
@Configuration
public class ShiroConfiguration {
/**
* Shiro的Web过滤器Factory 命名:shiroFilter
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//Shiro的核心安全接口,这个属性是必须的
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("authc", new AjaxPermissionsAuthorizationFilter());
shiroFilterFactoryBean.setFilters(filterMap);
/*定义shiro过滤链 Map结构
* Map中key(xml中是指value值)的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的
* anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种
* authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
*/
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
/* 过滤链定义,从上向下顺序执行,一般将 / ** 放在最为下边:这是一个坑呢,一不小心代码就不好使了;
authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问 */
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login/auth", "anon");
filterChainDefinitionMap.put("/login/logout", "anon");
filterChainDefinitionMap.put("/error", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 不指定名字的话,自动创建一个方法名第一个字母小写的bean
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm());
return securityManager;
}
/**
* Shiro Realm 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的
*/
@Bean
public UserRealm userRealm() {
UserRealm userRealm = new UserRealm();
return userRealm;
}
/**
* 凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* 所以我们需要修改下doGetAuthenticationInfo中的代码;
* )
* 可以扩展凭证匹配器,实现 输入密码错误次数后锁定等功能,下一次
*/
@Bean(name = "credentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列的次数,比如散列两次,相当于 md5(md5(""));
hashedCredentialsMatcher.setHashIterations(2);
//storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
/**
* Shiro生命周期处理器
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}
shiro.UserRealm
package com.heeexy.example.config.shiro;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.service.LoginService;
import com.heeexy.example.util.constants.Constants;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
/**
* @author: hxy
* @description: 自定义Realm
* @date: 2017/10/24 10:06
*/
public class UserRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(UserRealm.class);
@Autowired
private LoginService loginService;
@Override
@SuppressWarnings("unchecked")
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Session session = SecurityUtils.getSubject().getSession();
//查询用户的权限
JSONObject permission = (JSONObject) session.getAttribute(Constants.SESSION_USER_PERMISSION);
logger.info("permission的值为:" + permission);
logger.info("本用户权限为:" + permission.get("permissionList"));
//为当前用户设置角色和权限
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addStringPermissions((Collection<String>) permission.get("permissionList"));
return authorizationInfo;
}
/**
* 验证当前登录的Subject
* LoginController.login()方法中执行Subject.login()时 执行此方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
String loginName = (String) authcToken.getPrincipal();
// 获取用户密码
String password = new String((char[]) authcToken.getCredentials());
JSONObject user = loginService.getUser(loginName, password);
if (user == null) {
//没找到帐号
throw new UnknownAccountException();
}
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getString("username"),
user.getString("password"),
//ByteSource.Util.bytes("salt"), salt=username+salt,采用明文访问时,不需要此句
getName()
);
//session中不需要保存密码
user.remove("password");
//将用户信息放入session中
SecurityUtils.getSubject().getSession().setAttribute(Constants.SESSION_USER_INFO, user);
return authenticationInfo;
}
}
system.defaultView
package com.heeexy.example.config.system;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @author: hxy
* @description: 设置首页
* @date: 2017/10/24 10:28
*/
@Configuration
public class DefaultView extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
}
controller三个贴一起
package com.heeexy.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.service.ArticleService;
import com.heeexy.example.util.CommonUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* @author: hxy
* @description: 文章相关Controller
* @date: 2017/10/24 16:04
*/
@RestController
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
/**
* 查询文章列表
*/
@RequiresPermissions("article:list")
@GetMapping("/listArticle")
public JSONObject listArticle(HttpServletRequest request) {
return articleService.listArticle(CommonUtil.request2Json(request));
}
/**
* 新增文章
*/
@RequiresPermissions("article:add")
@PostMapping("/addArticle")
public JSONObject addArticle(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "content");
return articleService.addArticle(requestJson);
}
/**
* 修改文章
*/
@RequiresPermissions("article:update")
@PostMapping("/updateArticle")
public JSONObject updateArticle(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "id,content");
return articleService.updateArticle(requestJson);
}
}
package com.heeexy.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.service.LoginService;
import com.heeexy.example.util.CommonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: hxy
* @description: 登录相关Controller
* @date: 2017/10/24 10:33
*/
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
private LoginService loginService;
/**
* 登录
*/
@PostMapping("/auth")
public JSONObject authLogin(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "username,password");
return loginService.authLogin(requestJson);
}
/**
* 查询当前登录用户的信息
*/
@PostMapping("/getInfo")
public JSONObject getInfo() {
return loginService.getInfo();
}
/**
* 登出
*/
@PostMapping("/logout")
public JSONObject logout() {
return loginService.logout();
}
}
package com.heeexy.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.service.UserService;
import com.heeexy.example.util.CommonUtil;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* @author: hxy
* @description: 用户/角色/权限相关controller
* @date: 2017/11/2 10:19
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 查询用户列表
*/
@RequiresPermissions("user:list")
@GetMapping("/list")
public JSONObject listUser(HttpServletRequest request) {
return userService.listUser(CommonUtil.request2Json(request));
}
@RequiresPermissions("user:add")
@PostMapping("/addUser")
public JSONObject addUser(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "username, password, nickname, roleId");
return userService.addUser(requestJson);
}
@RequiresPermissions("user:update")
@PostMapping("/updateUser")
public JSONObject updateUser(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, " nickname, roleId, deleteStatus, userId");
return userService.updateUser(requestJson);
}
@RequiresPermissions(value = {"user:add", "user:update"}, logical = Logical.OR)
@GetMapping("/getAllRoles")
public JSONObject getAllRoles() {
return userService.getAllRoles();
}
/**
* 角色列表
*/
@RequiresPermissions("role:list")
@GetMapping("/listRole")
public JSONObject listRole() {
return userService.listRole();
}
/**
* 查询所有权限, 给角色分配权限时调用
*/
@RequiresPermissions("role:list")
@GetMapping("/listAllPermission")
public JSONObject listAllPermission() {
return userService.listAllPermission();
}
/**
* 新增角色
*/
@RequiresPermissions("role:add")
@PostMapping("/addRole")
public JSONObject addRole(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "roleName,permissions");
return userService.addRole(requestJson);
}
/**
* 修改角色
*/
@RequiresPermissions("role:update")
@PostMapping("/updateRole")
public JSONObject updateRole(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "roleId,roleName,permissions");
return userService.updateRole(requestJson);
}
/**
* 删除角色
*/
@RequiresPermissions("role:delete")
@PostMapping("/deleteRole")
public JSONObject deleteRole(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "roleId");
return userService.deleteRole(requestJson);
}
}
dao层,四个贴一起
package com.heeexy.example.dao;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
/**
* @author: hxy
* @description: 文章Dao层
* @date: 2017/10/24 16:06
*/
public interface ArticleDao {
/**
* 新增文章
*/
int addArticle(JSONObject jsonObject);
/**
* 统计文章总数
*/
int countArticle(JSONObject jsonObject);
/**
* 文章列表
*/
List<JSONObject> listArticle(JSONObject jsonObject);
/**
* 更新文章
*/
int updateArticle(JSONObject jsonObject);
}
package com.heeexy.example.dao;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
/**
* @author: hxy
* @description: 登录相关dao
* @date: 2017/10/24 11:02
*/
public interface LoginDao {
/**
* 根据用户名和密码查询对应的用户
*/
JSONObject getUser(@Param("username") String username, @Param("password") String password);
}
package com.heeexy.example.dao;
import com.alibaba.fastjson.JSONObject;
import java.util.Set;
/**
* @author: hxy
* @date: 2017/10/30 13:28
*/
public interface PermissionDao {
/**
* 查询用户的角色 菜单 权限
*/
JSONObject getUserPermission(String username);
/**
* 查询所有的菜单
*/
Set<String> getAllMenu();
/**
* 查询所有的权限
*/
Set<String> getAllPermission();
}
package com.heeexy.example.dao;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author: hxy
* @description: 用户/角色/权限
* @date: 2017-11-14 15:08:45
*/
public interface UserDao {
/**
* 查询用户数量
*/
int countUser(JSONObject jsonObject);
/**
* 查询用户列表
*/
List<JSONObject> listUser(JSONObject jsonObject);
/**
* 查询所有的角色
* 在添加/修改用户的时候要使用此方法
*/
List<JSONObject> getAllRoles();
/**
* 校验用户名是否已存在
*/
int queryExistUsername(JSONObject jsonObject);
/**
* 新增用户
*/
int addUser(JSONObject jsonObject);
/**
* 修改用户
*/
int updateUser(JSONObject jsonObject);
/**
* 角色列表
*/
List<JSONObject> listRole();
/**
* 查询所有权限, 给角色分配权限时调用
*/
List<JSONObject> listAllPermission();
/**
* 新增角色
*/
int insertRole(JSONObject jsonObject);
/**
* 批量插入角色的权限
*
* @param roleId 角色ID
* @param permissions 权限
*/
int insertRolePermission(@Param("roleId") String roleId, @Param("permissions") List<Integer> permissions);
/**
* 将角色曾经拥有而修改为不再拥有的权限 delete_status改为'2'
*/
int removeOldPermission(@Param("roleId") String roleId, @Param("permissions") List<Integer> permissions);
/**
* 修改角色名称
*/
int updateRoleName(JSONObject jsonObject);
/**
* 查询某角色的全部数据
* 在删除和修改角色时调用
*/
JSONObject getRoleAllInfo(JSONObject jsonObject);
/**
* 删除角色
*/
int removeRole(JSONObject jsonObject);
/**
* 删除本角色全部权限
*/
int removeRoleAllPermission(JSONObject jsonObject);
}
service包下四个也贴一起
package com.heeexy.example.service;
import com.alibaba.fastjson.JSONObject;
/**
* @author: hxy
* @date: 2017/10/24 16:06
*/
public interface ArticleService {
/**
* 新增文章
*/
JSONObject addArticle(JSONObject jsonObject);
/**
* 文章列表
*/
JSONObject listArticle(JSONObject jsonObject);
/**
* 更新文章
*/
JSONObject updateArticle(JSONObject jsonObject);
}
package com.heeexy.example.service;
import com.alibaba.fastjson.JSONObject;
/**
* @author: hxy
* @description: 登录Service
* @date: 2017/10/24 11:02
*/
public interface LoginService {
/**
* 登录表单提交
*/
JSONObject authLogin(JSONObject jsonObject);
/**
* 根据用户名和密码查询对应的用户
*
* @param username 用户名
* @param password 密码
*/
JSONObject getUser(String username, String password);
/**
* 查询当前登录用户的权限等信息
*/
JSONObject getInfo();
/**
* 退出登录
*/
JSONObject logout();
}
package com.heeexy.example.service;
import com.alibaba.fastjson.JSONObject;
/**
* @author: hxy
* @date: 2017/10/30 13:10
*/
public interface PermissionService {
/**
* 查询某用户的 角色 菜单列表 权限列表
*/
JSONObject getUserPermission(String username);
}
package com.heeexy.example.service;
import com.alibaba.fastjson.JSONObject;
/**
* @author: hxy
* @description: 用户/角色/权限
* @date: 2017/11/2 10:18
*/
public interface UserService {
/**
* 用户列表
*/
JSONObject listUser(JSONObject jsonObject);
/**
* 查询所有的角色
* 在添加/修改用户的时候要使用此方法
*/
JSONObject getAllRoles();
/**
* 添加用户
*/
JSONObject addUser(JSONObject jsonObject);
/**
* 修改用户
*/
JSONObject updateUser(JSONObject jsonObject);
/**
* 角色列表
*/
JSONObject listRole();
/**
* 查询所有权限, 给角色分配权限时调用
*/
JSONObject listAllPermission();
/**
* 添加角色
*/
JSONObject addRole(JSONObject jsonObject);
/**
* 修改角色
*/
JSONObject updateRole(JSONObject jsonObject);
/**
* 删除角色
*/
JSONObject deleteRole(JSONObject jsonObject);
}
service包下impl四个贴一起
package com.heeexy.example.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.dao.ArticleDao;
import com.heeexy.example.service.ArticleService;
import com.heeexy.example.util.CommonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author: hxy
* @date: 2017/10/24 16:07
*/
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleDao articleDao;
/**
* 新增文章
*/
@Override
@Transactional(rollbackFor = Exception.class)
public JSONObject addArticle(JSONObject jsonObject) {
articleDao.addArticle(jsonObject);
return CommonUtil.successJson();
}
/**
* 文章列表
*/
@Override
public JSONObject listArticle(JSONObject jsonObject) {
CommonUtil.fillPageParam(jsonObject);
int count = articleDao.countArticle(jsonObject);
List<JSONObject> list = articleDao.listArticle(jsonObject);
return CommonUtil.successPage(jsonObject, list, count);
}
/**
* 更新文章
*/
@Override
@Transactional(rollbackFor = Exception.class)
public JSONObject updateArticle(JSONObject jsonObject) {
articleDao.updateArticle(jsonObject);
return CommonUtil.successJson();
}
}
package com.heeexy.example.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.dao.LoginDao;
import com.heeexy.example.service.LoginService;
import com.heeexy.example.service.PermissionService;
import com.heeexy.example.util.CommonUtil;
import com.heeexy.example.util.constants.Constants;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author: hxy
* @description: 登录service实现类
* @date: 2017/10/24 11:53
*/
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private LoginDao loginDao;
@Autowired
private PermissionService permissionService;
/**
* 登录表单提交
*/
@Override
public JSONObject authLogin(JSONObject jsonObject) {
String username = jsonObject.getString("username");
String password = jsonObject.getString("password");
JSONObject info = new JSONObject();
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
currentUser.login(token);
info.put("result", "success");
} catch (AuthenticationException e) {
info.put("result", "fail");
}
return CommonUtil.successJson(info);
}
/**
* 根据用户名和密码查询对应的用户
*/
@Override
public JSONObject getUser(String username, String password) {
return loginDao.getUser(username, password);
}
/**
* 查询当前登录用户的权限等信息
*/
@Override
public JSONObject getInfo() {
//从session获取用户信息
Session session = SecurityUtils.getSubject().getSession();
JSONObject userInfo = (JSONObject) session.getAttribute(Constants.SESSION_USER_INFO);
String username = userInfo.getString("username");
JSONObject info = new JSONObject();
JSONObject userPermission = permissionService.getUserPermission(username);
session.setAttribute(Constants.SESSION_USER_PERMISSION, userPermission);
info.put("userPermission", userPermission);
return CommonUtil.successJson(info);
}
/**
* 退出登录
*/
@Override
public JSONObject logout() {
try {
Subject currentUser = SecurityUtils.getSubject();
currentUser.logout();
} catch (Exception e) {
}
return CommonUtil.successJson();
}
}
package com.heeexy.example.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.dao.PermissionDao;
import com.heeexy.example.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* @author: hxy
* @date: 2017/10/30 13:15
*/
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private PermissionDao permissionDao;
/**
* 查询某用户的 角色 菜单列表 权限列表
*/
@Override
public JSONObject getUserPermission(String username) {
JSONObject userPermission = getUserPermissionFromDB(username);
return userPermission;
}
/**
* 从数据库查询用户权限信息
*/
private JSONObject getUserPermissionFromDB(String username) {
JSONObject userPermission = permissionDao.getUserPermission(username);
//管理员角色ID为1
int adminRoleId = 1;
//如果是管理员
String roleIdKey = "roleId";
if (adminRoleId == userPermission.getIntValue(roleIdKey)) {
//查询所有菜单 所有权限
Set<String> menuList = permissionDao.getAllMenu();
Set<String> permissionList = permissionDao.getAllPermission();
userPermission.put("menuList", menuList);
userPermission.put("permissionList", permissionList);
}
return userPermission;
}
}
package com.heeexy.example.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.dao.UserDao;
import com.heeexy.example.service.UserService;
import com.heeexy.example.util.CommonUtil;
import com.heeexy.example.util.constants.ErrorEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author: hxy
* @description: 用户/角色/权限
* @date: 2017/11/2 10:18
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
/**
* 用户列表
*/
@Override
public JSONObject listUser(JSONObject jsonObject) {
CommonUtil.fillPageParam(jsonObject);
int count = userDao.countUser(jsonObject);
List<JSONObject> list = userDao.listUser(jsonObject);
return CommonUtil.successPage(jsonObject, list, count);
}
/**
* 添加用户
*/
@Override
public JSONObject addUser(JSONObject jsonObject) {
int exist = userDao.queryExistUsername(jsonObject);
if (exist > 0) {
return CommonUtil.errorJson(ErrorEnum.E_10009);
}
userDao.addUser(jsonObject);
return CommonUtil.successJson();
}
/**
* 查询所有的角色
* 在添加/修改用户的时候要使用此方法
*/
@Override
public JSONObject getAllRoles() {
List<JSONObject> roles = userDao.getAllRoles();
return CommonUtil.successPage(roles);
}
/**
* 修改用户
*/
@Override
public JSONObject updateUser(JSONObject jsonObject) {
userDao.updateUser(jsonObject);
return CommonUtil.successJson();
}
/**
* 角色列表
*/
@Override
public JSONObject listRole() {
List<JSONObject> roles = userDao.listRole();
return CommonUtil.successPage(roles);
}
/**
* 查询所有权限, 给角色分配权限时调用
*/
@Override
public JSONObject listAllPermission() {
List<JSONObject> permissions = userDao.listAllPermission();
return CommonUtil.successPage(permissions);
}
/**
* 添加角色
*/
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings("unchecked")
@Override
public JSONObject addRole(JSONObject jsonObject) {
userDao.insertRole(jsonObject);
userDao.insertRolePermission(jsonObject.getString("roleId"), (List<Integer>) jsonObject.get("permissions"));
return CommonUtil.successJson();
}
/**
* 修改角色
*/
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings("unchecked")
@Override
public JSONObject updateRole(JSONObject jsonObject) {
String roleId = jsonObject.getString("roleId");
List<Integer> newPerms = (List<Integer>) jsonObject.get("permissions");
JSONObject roleInfo = userDao.getRoleAllInfo(jsonObject);
Set<Integer> oldPerms = (Set<Integer>) roleInfo.get("permissionIds");
//修改角色名称
dealRoleName(jsonObject, roleInfo);
//添加新权限
saveNewPermission(roleId, newPerms, oldPerms);
//移除旧的不再拥有的权限
removeOldPermission(roleId, newPerms, oldPerms);
return CommonUtil.successJson();
}
/**
* 修改角色名称
*/
private void dealRoleName(JSONObject paramJson, JSONObject roleInfo) {
String roleName = paramJson.getString("roleName");
if (!roleName.equals(roleInfo.getString("roleName"))) {
userDao.updateRoleName(paramJson);
}
}
/**
* 为角色添加新权限
*/
private void saveNewPermission(String roleId, Collection<Integer> newPerms, Collection<Integer> oldPerms) {
List<Integer> waitInsert = new ArrayList<>();
for (Integer newPerm : newPerms) {
if (!oldPerms.contains(newPerm)) {
waitInsert.add(newPerm);
}
}
if (waitInsert.size() > 0) {
userDao.insertRolePermission(roleId, waitInsert);
}
}
/**
* 删除角色 旧的 不再拥有的权限
*/
private void removeOldPermission(String roleId, Collection<Integer> newPerms, Collection<Integer> oldPerms) {
List<Integer> waitRemove = new ArrayList<>();
for (Integer oldPerm : oldPerms) {
if (!newPerms.contains(oldPerm)) {
waitRemove.add(oldPerm);
}
}
if (waitRemove.size() > 0) {
userDao.removeOldPermission(roleId, waitRemove);
}
}
/**
* 删除角色
*/
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings("unchecked")
@Override
public JSONObject deleteRole(JSONObject jsonObject) {
JSONObject roleInfo = userDao.getRoleAllInfo(jsonObject);
List<JSONObject> users = (List<JSONObject>) roleInfo.get("users");
if (users != null && users.size() > 0) {
return CommonUtil.errorJson(ErrorEnum.E_10008);
}
userDao.removeRole(jsonObject);
userDao.removeRoleAllPermission(jsonObject);
return CommonUtil.successJson();
}
}
util包下两个贴一起
package com.heeexy.example.util;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.config.exception.CommonJsonException;
import com.heeexy.example.util.constants.Constants;
import com.heeexy.example.util.constants.ErrorEnum;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.List;
/**
* @author: hxy
* @description: 本后台接口系统常用的json工具类
* @date: 2017/10/24 10:12
*/
public class CommonUtil {
/**
* 返回一个info为空对象的成功消息的json
*/
public static JSONObject successJson() {
return successJson(new JSONObject());
}
/**
* 返回一个返回码为100的json
*/
public static JSONObject successJson(Object info) {
JSONObject resultJson = new JSONObject();
resultJson.put("code", Constants.SUCCESS_CODE);
resultJson.put("msg", Constants.SUCCESS_MSG);
resultJson.put("info", info);
return resultJson;
}
/**
* 返回错误信息JSON
*/
public static JSONObject errorJson(ErrorEnum errorEnum) {
JSONObject resultJson = new JSONObject();
resultJson.put("code", errorEnum.getErrorCode());
resultJson.put("msg", errorEnum.getErrorMsg());
resultJson.put("info", new JSONObject());
return resultJson;
}
/**
* 查询分页结果后的封装工具方法
*
* @param requestJson 请求参数json,此json在之前调用fillPageParam 方法时,已经将pageRow放入
* @param list 查询分页对象list
* @param totalCount 查询出记录的总条数
*/
public static JSONObject successPage(final JSONObject requestJson, List<JSONObject> list, int totalCount) {
int pageRow = requestJson.getIntValue("pageRow");
int totalPage = getPageCounts(pageRow, totalCount);
JSONObject result = successJson();
JSONObject info = new JSONObject();
info.put("list", list);
info.put("totalCount", totalCount);
info.put("totalPage", totalPage);
result.put("info", info);
return result;
}
/**
* 查询分页结果后的封装工具方法
*
* @param list 查询分页对象list
*/
public static JSONObject successPage(List<JSONObject> list) {
JSONObject result = successJson();
JSONObject info = new JSONObject();
info.put("list", list);
result.put("info", info);
return result;
}
/**
* 获取总页数
*
* @param pageRow 每页行数
* @param itemCount 结果的总条数
*/
private static int getPageCounts(int pageRow, int itemCount) {
if (itemCount == 0) {
return 1;
}
return itemCount % pageRow > 0 ?
itemCount / pageRow + 1 :
itemCount / pageRow;
}
/**
* 将request参数值转为json
*/
public static JSONObject request2Json(HttpServletRequest request) {
JSONObject requestJson = new JSONObject();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] pv = request.getParameterValues(paramName);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < pv.length; i++) {
if (pv[i].length() > 0) {
if (i > 0) {
sb.append(",");
}
sb.append(pv[i]);
}
}
requestJson.put(paramName, sb.toString());
}
return requestJson;
}
/**
* 将request转JSON
* 并且验证非空字段
*/
public static JSONObject convert2JsonAndCheckRequiredColumns(HttpServletRequest request, String requiredColumns) {
JSONObject jsonObject = request2Json(request);
hasAllRequired(jsonObject, requiredColumns);
return jsonObject;
}
/**
* 验证是否含有全部必填字段
*
* @param requiredColumns 必填的参数字段名称 逗号隔开 比如"userId,name,telephone"
*/
public static void hasAllRequired(final JSONObject jsonObject, String requiredColumns) {
if (!StringTools.isNullOrEmpty(requiredColumns)) {
//验证字段非空
String[] columns = requiredColumns.split(",");
String missCol = "";
for (String column : columns) {
Object val = jsonObject.get(column.trim());
if (StringTools.isNullOrEmpty(val)) {
missCol += column + " ";
}
}
if (!StringTools.isNullOrEmpty(missCol)) {
jsonObject.clear();
jsonObject.put("code", ErrorEnum.E_90003.getErrorCode());
jsonObject.put("msg", "缺少必填参数:" + missCol.trim());
jsonObject.put("info", new JSONObject());
throw new CommonJsonException(jsonObject);
}
}
}
/**
* 在分页查询之前,为查询条件里加上分页参数
*
* @param paramObject 查询条件json
* @param defaultPageRow 默认的每页条数,即前端不传pageRow参数时的每页条数
*/
private static void fillPageParam(final JSONObject paramObject, int defaultPageRow) {
int pageNum = paramObject.getIntValue("pageNum");
pageNum = pageNum == 0 ? 1 : pageNum;
int pageRow = paramObject.getIntValue("pageRow");
pageRow = pageRow == 0 ? defaultPageRow : pageRow;
paramObject.put("offSet", (pageNum - 1) * pageRow);
paramObject.put("pageRow", pageRow);
paramObject.put("pageNum", pageNum);
//删除此参数,防止前端传了这个参数,pageHelper分页插件检测到之后,拦截导致SQL错误
paramObject.remove("pageSize");
}
/**
* 分页查询之前的处理参数
* 没有传pageRow参数时,默认每页10条.
*/
public static void fillPageParam(final JSONObject paramObject) {
fillPageParam(paramObject, 10);
}
}
package com.heeexy.example.util;
/**
* @author: hxy
* @date: 2017/10/24 10:16
*/
public class StringTools {
public static boolean isNullOrEmpty(String str) {
return null == str || "".equals(str) || "null".equals(str);
}
public static boolean isNullOrEmpty(Object obj) {
return null == obj || "".equals(obj);
}
}
util包下的constans两个贴一起
package com.heeexy.example.util.constants;
/**
* @author: hxy
* @description: 通用常量类, 单个业务的常量请单开一个类, 方便常量的分类管理
* @date: 2017/10/24 10:15
*/
public class Constants {
public static final String SUCCESS_CODE = "100";
public static final String SUCCESS_MSG = "请求成功";
/**
* session中存放用户信息的key值
*/
public static final String SESSION_USER_INFO = "userInfo";
public static final String SESSION_USER_PERMISSION = "userPermission";
}
package com.heeexy.example.util.constants;
/**
* @author: hxy
* @date: 2017/10/24 10:16
*/
public enum ErrorEnum {
/*
* 错误信息
* */
E_400("400", "请求处理异常,请稍后再试"),
E_500("500", "请求方式有误,请检查 GET/POST"),
E_501("501", "请求路径不存在"),
E_502("502", "权限不足"),
E_10008("10008", "角色删除失败,尚有用户属于此角色"),
E_10009("10009", "账户已存在"),
E_20011("20011", "登陆已过期,请重新登陆"),
E_90003("90003", "缺少必填参数");
private String errorCode;
private String errorMsg;
ErrorEnum(String errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}
util包下的model两个贴一起
package com.heeexy.example.util;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.config.exception.CommonJsonException;
import com.heeexy.example.util.constants.Constants;
import com.heeexy.example.util.constants.ErrorEnum;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.List;
/**
* @author: hxy
* @description: 本后台接口系统常用的json工具类
* @date: 2017/10/24 10:12
*/
public class CommonUtil {
/**
* 返回一个info为空对象的成功消息的json
*/
public static JSONObject successJson() {
return successJson(new JSONObject());
}
/**
* 返回一个返回码为100的json
*/
public static JSONObject successJson(Object info) {
JSONObject resultJson = new JSONObject();
resultJson.put("code", Constants.SUCCESS_CODE);
resultJson.put("msg", Constants.SUCCESS_MSG);
resultJson.put("info", info);
return resultJson;
}
/**
* 返回错误信息JSON
*/
public static JSONObject errorJson(ErrorEnum errorEnum) {
JSONObject resultJson = new JSONObject();
resultJson.put("code", errorEnum.getErrorCode());
resultJson.put("msg", errorEnum.getErrorMsg());
resultJson.put("info", new JSONObject());
return resultJson;
}
/**
* 查询分页结果后的封装工具方法
*
* @param requestJson 请求参数json,此json在之前调用fillPageParam 方法时,已经将pageRow放入
* @param list 查询分页对象list
* @param totalCount 查询出记录的总条数
*/
public static JSONObject successPage(final JSONObject requestJson, List<JSONObject> list, int totalCount) {
int pageRow = requestJson.getIntValue("pageRow");
int totalPage = getPageCounts(pageRow, totalCount);
JSONObject result = successJson();
JSONObject info = new JSONObject();
info.put("list", list);
info.put("totalCount", totalCount);
info.put("totalPage", totalPage);
result.put("info", info);
return result;
}
/**
* 查询分页结果后的封装工具方法
*
* @param list 查询分页对象list
*/
public static JSONObject successPage(List<JSONObject> list) {
JSONObject result = successJson();
JSONObject info = new JSONObject();
info.put("list", list);
result.put("info", info);
return result;
}
/**
* 获取总页数
*
* @param pageRow 每页行数
* @param itemCount 结果的总条数
*/
private static int getPageCounts(int pageRow, int itemCount) {
if (itemCount == 0) {
return 1;
}
return itemCount % pageRow > 0 ?
itemCount / pageRow + 1 :
itemCount / pageRow;
}
/**
* 将request参数值转为json
*/
public static JSONObject request2Json(HttpServletRequest request) {
JSONObject requestJson = new JSONObject();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] pv = request.getParameterValues(paramName);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < pv.length; i++) {
if (pv[i].length() > 0) {
if (i > 0) {
sb.append(",");
}
sb.append(pv[i]);
}
}
requestJson.put(paramName, sb.toString());
}
return requestJson;
}
/**
* 将request转JSON
* 并且验证非空字段
*/
public static JSONObject convert2JsonAndCheckRequiredColumns(HttpServletRequest request, String requiredColumns) {
JSONObject jsonObject = request2Json(request);
hasAllRequired(jsonObject, requiredColumns);
return jsonObject;
}
/**
* 验证是否含有全部必填字段
*
* @param requiredColumns 必填的参数字段名称 逗号隔开 比如"userId,name,telephone"
*/
public static void hasAllRequired(final JSONObject jsonObject, String requiredColumns) {
if (!StringTools.isNullOrEmpty(requiredColumns)) {
//验证字段非空
String[] columns = requiredColumns.split(",");
String missCol = "";
for (String column : columns) {
Object val = jsonObject.get(column.trim());
if (StringTools.isNullOrEmpty(val)) {
missCol += column + " ";
}
}
if (!StringTools.isNullOrEmpty(missCol)) {
jsonObject.clear();
jsonObject.put("code", ErrorEnum.E_90003.getErrorCode());
jsonObject.put("msg", "缺少必填参数:" + missCol.trim());
jsonObject.put("info", new JSONObject());
throw new CommonJsonException(jsonObject);
}
}
}
/**
* 在分页查询之前,为查询条件里加上分页参数
*
* @param paramObject 查询条件json
* @param defaultPageRow 默认的每页条数,即前端不传pageRow参数时的每页条数
*/
private static void fillPageParam(final JSONObject paramObject, int defaultPageRow) {
int pageNum = paramObject.getIntValue("pageNum");
pageNum = pageNum == 0 ? 1 : pageNum;
int pageRow = paramObject.getIntValue("pageRow");
pageRow = pageRow == 0 ? defaultPageRow : pageRow;
paramObject.put("offSet", (pageNum - 1) * pageRow);
paramObject.put("pageRow", pageRow);
paramObject.put("pageNum", pageNum);
//删除此参数,防止前端传了这个参数,pageHelper分页插件检测到之后,拦截导致SQL错误
paramObject.remove("pageSize");
}
/**
* 分页查询之前的处理参数
* 没有传pageRow参数时,默认每页10条.
*/
public static void fillPageParam(final JSONObject paramObject) {
fillPageParam(paramObject, 10);
}
}
package com.heeexy.example.util;
/**
* @author: hxy
* @date: 2017/10/24 10:16
*/
public class StringTools {
public static boolean isNullOrEmpty(String str) {
return null == str || "".equals(str) || "null".equals(str);
}
public static boolean isNullOrEmpty(Object obj) {
return null == obj || "".equals(obj);
}
}
mapper.ArticalMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.heeexy.example.dao.ArticleDao">
<insert id="addArticle" parameterType="com.alibaba.fastjson.JSONObject">
INSERT INTO article
(content)
VALUES
(#{content})
</insert>
<select id="countArticle" resultType="Integer">
SELECT count(0)
FROM article w
WHERE w.delete_status = '1'
</select>
<select id="listArticle" resultType="com.alibaba.fastjson.JSONObject">
SELECT
w.id id,
w.content content,
date_format(w.create_time, '%Y.%m.%d %T') createTime
FROM article w
WHERE w.delete_status = '1'
ORDER BY w.id DESC
LIMIT #{offSet}, #{pageRow}
</select>
<update id="updateArticle" parameterType="com.alibaba.fastjson.JSONObject">
UPDATE article
SET
content = #{content}
WHERE id = #{id}
</update>
</mapper>
mapper.LoginMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.heeexy.example.dao.LoginDao">
<select id="getUser" resultType="com.alibaba.fastjson.JSONObject">
SELECT
u.id userId,
u.username username,
u.password password,
u.nickname nickName
FROM
sys_user u
WHERE u.username = #{username}
AND u.password = #{password}
AND u.delete_status = '1'
</select>
</mapper>
mapper.PermissionMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.heeexy.example.dao.PermissionDao">
<resultMap id="permissionMap" type="com.heeexy.example.util.model.One2Many">
<id column="userId" property="userId"/>
<result column="nickname" property="nickname"/>
<result column="roleId" property="roleId"/>
<result column="roleName" property="roleName"/>
<collection property="menuList" ofType="String">
<id column="menuCode" property="menuCode"/>
</collection>
<collection property="permissionList" ofType="String">
<id column="permissionCode" property="permissionCode"/>
</collection>
</resultMap>
<select id="getUserPermission" resultMap="permissionMap">
SELECT
u.id userId,
u.nickname nickname,
u.role_id roleId,
r.role_name roleName,
p.menu_code menuCode,
p.permission_code permissionCode
FROM sys_user u
LEFT JOIN sys_role r ON r.id = u.role_id
LEFT JOIN sys_role_permission rp ON u.role_id = rp.role_id
LEFT JOIN sys_permission p ON rp.permission_id = p.id AND rp.delete_status = '1'
WHERE u.username = #{username}
AND u.delete_status = '1'
</select>
<select id="getAllPermission" resultType="String">
SELECT p.permission_code permissionCode
FROM sys_permission p
ORDER BY p.id
</select>
<select id="getAllMenu" resultType="String">
SELECT p.menu_code menuCode
FROM sys_permission p
ORDER BY p.id
</select>
</mapper>
mapper.UserMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.heeexy.example.dao.UserDao">
<select id="countUser" resultType="Integer">
SELECT count(0)
FROM sys_user u
WHERE u.delete_status = '1'
</select>
<resultMap id="userMap" type="com.heeexy.example.util.model.One2Many">
<id column="userId" property="userId"/>
<result column="username" property="username"/>
<result column="nickname" property="nickname"/>
<result column="roleId" property="roleId"/>
<result column="roleName" property="roleName"/>
<result column="createTime" property="createTime"/>
<result column="updateTime" property="updateTime"/>
<result column="lastLoginTime" property="lastLoginTime"/>
<result column="deleteStatus" property="deleteStatus"/>
<collection property="permissionList" ofType="String">
<id column="permissionName" property="permissionName"/>
</collection>
</resultMap>
<select id="listUser" resultMap="userMap">
SELECT
u.*,
r.role_name roleName,
CONCAT(p.menu_name, p.permission_name) permissionName
FROM (
SELECT
id userId,
username username,
nickname nickname,
role_id roleId,
delete_status deleteStatus,
DATE_FORMAT(create_time, '%Y.%m.%d %T') createTime,
DATE_FORMAT(update_time, '%Y.%m.%d %T') updateTime
FROM sys_user
WHERE delete_status = '1'
ORDER BY id
LIMIT #{offSet}, #{pageRow}
) u
LEFT JOIN sys_role r ON r.id = u.roleId
LEFT JOIN sys_role_permission rp ON rp.role_id = r.id
LEFT JOIN sys_permission p ON p.id = rp.permission_id
ORDER BY u.userId
</select>
<select id="getAllRoles" resultType="com.alibaba.fastjson.JSONObject">
SELECT
id roleId,
role_name roleName
FROM sys_role
WHERE delete_status='1'
</select>
<insert id="addUser" useGeneratedKeys="true" keyProperty="userId">
INSERT INTO sys_user
(username, password, nickname, role_id) VALUES
(#{username}, #{password}, #{nickname}, #{roleId})
</insert>
<update id="updateUser">
UPDATE sys_user
SET
nickname = #{nickname}
<if test="password !='' and password !=null">
, password = #{password}
</if>
, role_id = #{roleId}
, delete_status = #{deleteStatus}
WHERE id = #{userId} and id != 10001
</update>
<resultMap id="roleMap" type="com.heeexy.example.util.model.One2Many">
<id column="roleId" property="roleId"/>
<result column="roleName" property="roleName"/>
<collection property="users" ofType="com.alibaba.fastjson.JSONObject">
<id column="userId" property="userId"/>
<result column="nickname" property="nickname"/>
</collection>
<collection property="menus" ofType="com.heeexy.example.util.model.One2Many">
<id column="menuCode" property="menuCode"/>
<result column="menuName" property="menuName"/>
<collection property="permissions" ofType="com.alibaba.fastjson.JSONObject">
<id column="permissionId" property="permissionId"/>
<result column="permissionName" property="permissionName"/>
</collection>
</collection>
</resultMap>
<select id="listRole" resultMap="roleMap">
SELECT
r.id roleId,
r.role_name roleName,
u.id userId,
u.nickname nickname,
p.id permissionId,
p.menu_code menuCode,
p.menu_name menuName,
p.permission_name permissionName
FROM sys_role r
LEFT JOIN sys_user u ON r.id = u.role_id AND u.delete_status = '1'
LEFT JOIN sys_role_permission rp ON r.id = rp.role_id AND rp.delete_status = '1'
LEFT JOIN sys_permission p ON rp.permission_id = p.id
WHERE r.delete_status = '1'
ORDER BY r.id, p.id
</select>
<resultMap id="permissionMap" type="com.heeexy.example.util.model.One2Many">
<id column="menuName" property="menuName"/>
<collection property="permissions" ofType="com.alibaba.fastjson.JSONObject">
<id column="id" property="id"/>
<result column="permissionName" property="permissionName"/>
<result column="requiredPerm" property="requiredPerm" javaType="Integer"/>
</collection>
</resultMap>
<select id="listAllPermission" resultMap="permissionMap">
SELECT
p.id id,
p.menu_name menuName,
p.permission_name permissionName,
p.required_permission requiredPerm
FROM sys_permission p;
</select>
<insert id="insertRole" useGeneratedKeys="true" keyProperty="roleId">
INSERT INTO sys_role
(role_name)
VALUES (#{roleName})
</insert>
<insert id="insertRolePermission">
insert into sys_role_permission (role_id, permission_id)
values
<foreach collection="permissions" item="item" index="index" separator=",">
(#{roleId}, #{item})
</foreach>
</insert>
<resultMap id="aRole" type="com.heeexy.example.util.model.One2Many">
<id column="roleId" property="roleId"/>
<result column="roleName" property="roleName"/>
<collection property="users" ofType="com.alibaba.fastjson.JSONObject">
<id column="userId" property="userId"/>
</collection>
<collection property="permissionIds" ofType="Integer">
<id column="permissionId" property="permissionId"/>
</collection>
</resultMap>
<select id="getRoleAllInfo" resultMap="aRole">
SELECT
r.id roleId,
r.role_name roleName,
u.id userId,
p.id permissionId
FROM sys_role r
LEFT JOIN sys_user u ON r.id = u.role_id AND u.delete_status = '1'
LEFT JOIN sys_role_permission rp ON r.id = rp.role_id AND rp.delete_status = '1'
LEFT JOIN sys_permission p ON rp.permission_id = p.id
WHERE r.id = #{roleId}
</select>
<update id="removeRole">
UPDATE sys_role
SET
delete_status = '2'
WHERE id = #{roleId} and id !=1
</update>
<update id="removeRoleAllPermission">
UPDATE sys_role_permission
SET
delete_status = '2'
WHERE role_id = #{roleId}
</update>
<update id="removeOldPermission">
UPDATE sys_role_permission
SET
delete_status = '2'
WHERE role_id = #{roleId}
AND permission_id in (
<foreach collection="permissions" item="item" index="index" separator=",">
#{item}
</foreach>
)
</update>
<update id="updateRoleName">
UPDATE sys_role
SET
role_name = #{roleName}
WHERE id = #{roleId}
</update>
<select id="queryExistUsername" resultType="int">
select count(0)
from sys_user
WHERE username=#{username}
AND delete_status='1';
</select>
</mapper>
ApplicaitonMian()
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 注意这里要指向原先用main方法执行的Application启动类
return builder.sources(MyApplication.class);
}
sql
# Host: 127.0.0.1 (Version 5.6.35)
# Date: 2017-11-22 16:38:47
# Generator: MySQL-Front 5.4 (Build 4.153) - http://www.mysqlfront.de/
/*!40101 SET NAMES utf8 */;
#
# Structure for table "article"
#
DROP TABLE IF EXISTS `article`;
CREATE TABLE `article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(255) DEFAULT '' COMMENT '文章内容',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_status` varchar(1) DEFAULT '1' COMMENT '是否有效 1.有效 2无效',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COMMENT='发布号作者表';
#
# Data for table "article"
#
INSERT INTO `article` VALUES (5,'莎士比亚','2017-10-25 09:08:45','2017-10-30 17:59:41','1'),(6,'亚里士多德','2017-10-26 10:49:28','2017-11-18 09:54:15','1'),(10,'亚历山大','2017-10-26 14:57:45','2017-11-08 13:28:52','1'),(11,'李白','2017-10-26 15:23:42','2017-10-26 15:23:42','1'),(19,'文章test2','2017-11-18 13:37:07','2017-11-18 13:37:11','1');
#
# Structure for table "sys_permission"
#
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` int(11) NOT NULL DEFAULT '0' COMMENT '自定id,主要供前端展示权限列表分类排序使用.',
`menu_code` varchar(255) DEFAULT '' COMMENT '归属菜单,前端判断并展示菜单使用,',
`menu_name` varchar(255) DEFAULT '' COMMENT '菜单的中文释义',
`permission_code` varchar(255) DEFAULT '' COMMENT '权限的代码/通配符,对应代码中@RequiresPermissions 的value',
`permission_name` varchar(255) DEFAULT '' COMMENT '本权限的中文释义',
`required_permission` tinyint(1) DEFAULT '2' COMMENT '是否本菜单必选权限, 1.必选 2非必选 通常是"列表"权限是必选',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='后台权限表';
#
# Data for table "sys_permission"
#
INSERT INTO `sys_permission` VALUES (101,'article','文章管理','article:list','列表',1),(102,'article','文章管理','article:add','新增',2),(103,'article','文章管理','article:update','修改',2),(601,'user','用户','user:list','列表',1),(602,'user','用户','user:add','新增',2),(603,'user','用户','user:update','修改',2),(701,'role','角色权限','role:list','列表',1),(702,'role','角色权限','role:add','新增',2),(703,'role','角色权限','role:update','修改',2),(704,'role','角色权限','role:delete','删除',2);
#
# Structure for table "sys_role"
#
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(20) DEFAULT NULL COMMENT '角色名',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`delete_status` varchar(1) DEFAULT '1' COMMENT '是否有效 1有效 2无效',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='后台角色表';
#
# Data for table "sys_role"
#
INSERT INTO `sys_role` VALUES (1,'管理员','2017-11-22 16:24:34','2017-11-22 16:24:52','1'),(2,'作家','2017-11-22 16:24:34','2017-11-22 16:24:52','1'),(3,'程序员','2017-11-22 16:28:47','2017-11-22 16:28:47','1');
#
# Structure for table "sys_role_permission"
#
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL COMMENT '角色id',
`permission_id` int(11) DEFAULT NULL COMMENT '权限id',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`delete_status` varchar(1) DEFAULT '1' COMMENT '是否有效 1有效 2无效',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='角色-权限关联表';
#
# Data for table "sys_role_permission"
#
INSERT INTO `sys_role_permission` VALUES (1,2,101,'2017-11-22 16:26:21','2017-11-22 16:26:32','1'),(2,2,102,'2017-11-22 16:26:21','2017-11-22 16:26:32','1'),(5,2,602,'2017-11-22 16:28:28','2017-11-22 16:28:28','1'),(6,2,601,'2017-11-22 16:28:28','2017-11-22 16:28:28','1'),(7,2,603,'2017-11-22 16:28:28','2017-11-22 16:28:28','1'),(8,2,703,'2017-11-22 16:28:28','2017-11-22 16:28:28','1'),(9,2,701,'2017-11-22 16:28:28','2017-11-22 16:28:28','1'),(10,2,702,'2017-11-22 16:28:28','2017-11-22 16:28:28','1'),(11,2,704,'2017-11-22 16:28:31','2017-11-22 16:28:31','1'),(12,2,103,'2017-11-22 16:28:31','2017-11-22 16:28:31','1'),(13,3,601,'2017-11-22 16:28:47','2017-11-22 16:28:47','1'),(14,3,701,'2017-11-22 16:28:47','2017-11-22 16:28:47','1'),(15,3,702,'2017-11-22 16:35:01','2017-11-22 16:35:01','1'),(16,3,704,'2017-11-22 16:35:01','2017-11-22 16:35:01','1'),(17,3,102,'2017-11-22 16:35:01','2017-11-22 16:35:01','1'),(18,3,101,'2017-11-22 16:35:01','2017-11-22 16:35:01','1'),(19,3,603,'2017-11-22 16:35:01','2017-11-22 16:35:01','1');
#
# Structure for table "sys_user"
#
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`nickname` varchar(255) DEFAULT NULL COMMENT '昵称',
`role_id` int(11) DEFAULT '0' COMMENT '角色ID',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`delete_status` varchar(1) DEFAULT '1' COMMENT '是否有效 1有效 2无效',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10008 DEFAULT CHARSET=utf8 COMMENT='运营后台用户表';
#
# Data for table "sys_user"
#
INSERT INTO `sys_user` VALUES (10003,'admin','123456','超级用户23',1,'2017-10-30 11:52:38','2017-11-17 23:51:40','1'),(10004,'user','123456','莎士比亚',2,'2017-10-30 16:13:02','2017-11-18 02:48:24','1'),(10005,'aaa','123456','abba',1,'2017-11-15 14:02:56','2017-11-17 23:51:42','1'),(10007,'test','123456','就看看列表',3,'2017-11-22 16:29:41','2017-11-22 16:29:41','1');
第一:equals() 的作用是表示其他对象是否“等于”这个对象。在Object源码里面 equals的作用等价于 == 即 用来比较俩个对象的内存地址是否相同public boolean equals(Object obj) { return (this == obj);}但是一般我们是想用equals来表示 俩个对象的内容是否相同的 所以需要我们去...
原型:char * strtok(char * s,const char * ct)用途:在s中找出以ct中的字符为分隔的字符串,即是源串中除去了含有分隔串中的所有字符后余下的一段段的字符串,每调用一次找到一串,找不到则返回空串。第一次调用必须传给它有效的字符串,第二次传NU
http://acm.hdu.edu.cn/showproblem.php?pid=4359比赛的时候就悲剧了,当时我就卡在1006题上去了,然后这题也没心情去搞这题,估计当时我弄的话也搞不出来,表示关于这种 2叉树计数 做的题目还是很少,以后要加强这方面的练习,哭,看的解题报告才弄出来的,无语中……贴下官方的解题报告:Author: [email protected] Bri
题意:给一棵带权树,问每个点和所有标号小于它的点的带权lca和。分析:这种lca和可以看成是两段权值不同的链的差,这样我们用lct来维护树上每段链的带权重量和,每次插入一个点。#include#include#include#include#include#include#include#include#include#include#include#
Paillier于1999年提出,是一种概率非对称加密。计算第 n 个剩余类的问题在计算上是困难的。 判定性复合剩余假设 是难解的假设,这是Paillier的基础注1:剩余类注2:判定复合剩余假设
1、什么是MetaData答:描述数据的数据,目的是对数据进行管理,包括监控数据质量,数据流向,业务分析等.比如ETL Job的定义,日志等,再比如数据仓库主题,度量,维度的定义等. 2,在做陷阱的时候,尖刺要从陷阱中升起和下降,由于缓慢上升要用timeline,其中有两个连接,play和Playe from start,区别(1)最初的想法是拿到一百个尖刺数组,在foreac...
最近想着模仿QQ第一次在电脑登录时候的滑块验证效果如下主代码:PuzzleWidget.h#ifndef PUZZLEWIDGET_H#define PUZZLEWIDGET_H#include <QWidget>class PuzzleWidget : public QWidget{ Q_OBJECT Q_PROPERTY(QString pixmap READ...
机器学习十大算法之一:EM算法。能评得上十大之一,让人听起来觉得挺NB的。什么是NB啊,我们一般说某个人很NB,是因为他能解决一些别人解决不了的问题。神为什么是神,因为神能做很多人做不了的事。那么EM算法能解决什么问题呢?或者说EM算法是因为什么而来到这个世界上,还吸引了那么多世人的目光。我希望自己能通俗地把它理解或者说明白,但是,EM这个问题感觉真的不太好用通俗的语言去说明白,因为它很简单,又...
<!--pre.western {font-family:"AR PL UMing HK"}pre.cjk {font-family:"AR PL UMing HK"}pre.ctl {font-family:"AR PL UMing HK",monospace}p {margin-bottom:0.08in}-->接着上次AD7879-I2C对
JRE vs OpenJDK vs Oracle JDKJRE(Java Runtime Environment),它是你运行一个基于Java语言应用程序的所正常需要的环境。如果你不是一个程序员的话,这些足够你的需要。JDK代表Java开发工具包,如果你想做一些有关Java的开发(阅读程序),这正是你所需要的。OpenJDK是Java开发工具包的开源实现,Oracle JDK是Ja...
角色是保存权限的容器。如果为某个用户授予一个角色,那么为这个角色授予的所有权限都会自动应用于该用户。就角色而言,使用WITH ADMIN OPTION为角色授予的权限不能级联取消。Oracle 10G中的预定义角色及其被授予的权限角色被授予的权限DBA几乎所有系统权限以及某些角色SELECT_CATALOG_ROLE数据字典上的对象权限
[ERROR] JmCheckManageDaoImpl:901 - java.sql.SQLException: ORA-01400: 无法将 NULL 插入 ("CHARGE_WQRL"."SF_JMQTFY_T"."BH")这个问题很多时候是没有为该表建立触发器(trigger)导致的,或者是序列(sequence)没建立,查看一下,确保两个都要有。这是建立sequencec...