Commit d552b1db by fengshuonan

修改包名为cn

parent bb2d570a
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SpringBoot方式启动类
*
* @author stylefeng
* @Date 2017/5/21 12:06
*/
@SpringBootApplication
public class GunsApplication {
private final static Logger logger = LoggerFactory.getLogger(GunsApplication.class);
public static void main(String[] args) {
SpringApplication.run(GunsApplication.class, args);
logger.info("GunsApplication is success!");
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* Guns Web程序启动类
*
* @author fengshuonan
* @date 2017-05-21 9:43
*/
public class GunsServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(GunsApplication.class);
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.aop;
import cn.stylefeng.guns.core.log.LogManager;
import cn.stylefeng.guns.core.log.factory.LogTaskFactory;
import cn.stylefeng.guns.core.shiro.ShiroKit;
import cn.stylefeng.roses.core.reqres.response.ErrorResponseData;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import cn.stylefeng.guns.core.common.exception.BizExceptionEnum;
import cn.stylefeng.guns.core.common.exception.InvalidKaptchaException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.DisabledAccountException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.lang.reflect.UndeclaredThrowableException;
import static cn.stylefeng.roses.core.util.HttpContext.getIp;
import static cn.stylefeng.roses.core.util.HttpContext.getRequest;
/**
* 全局的的异常拦截器(拦截所有的控制器)(带有@RequestMapping注解的方法上都会拦截)
*
* @author fengshuonan
* @date 2016年11月12日 下午3:19:56
*/
@ControllerAdvice
@Order(-1)
public class GlobalExceptionHandler {
private Logger log = LoggerFactory.getLogger(this.getClass());
/**
* 拦截业务异常
*/
@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponseData bussiness(ServiceException e) {
LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
getRequest().setAttribute("tip", e.getMessage());
log.error("业务异常:", e);
return new ErrorResponseData(e.getCode(), e.getMessage());
}
/**
* 用户未登录异常
*/
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String unAuth(AuthenticationException e) {
log.error("用户未登陆:", e);
return "/login.html";
}
/**
* 账号被冻结异常
*/
@ExceptionHandler(DisabledAccountException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String accountLocked(DisabledAccountException e, Model model) {
String username = getRequest().getParameter("username");
LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号被冻结", getIp()));
model.addAttribute("tips", "账号被冻结");
return "/login.html";
}
/**
* 账号密码错误异常
*/
@ExceptionHandler(CredentialsException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String credentials(CredentialsException e, Model model) {
String username = getRequest().getParameter("username");
LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号密码错误", getIp()));
model.addAttribute("tips", "账号密码错误");
return "/login.html";
}
/**
* 验证码错误异常
*/
@ExceptionHandler(InvalidKaptchaException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String credentials(InvalidKaptchaException e, Model model) {
String username = getRequest().getParameter("username");
LogManager.me().executeLog(LogTaskFactory.loginLog(username, "验证码错误", getIp()));
model.addAttribute("tips", "验证码错误");
return "/login.html";
}
/**
* 无权访问该资源异常
*/
@ExceptionHandler(UndeclaredThrowableException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ResponseBody
public ErrorResponseData credentials(UndeclaredThrowableException e) {
getRequest().setAttribute("tip", "权限异常");
log.error("权限异常!", e);
return new ErrorResponseData(BizExceptionEnum.NO_PERMITION.getCode(), BizExceptionEnum.NO_PERMITION.getMessage());
}
/**
* 拦截未知的运行时异常
*/
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponseData notFount(RuntimeException e) {
LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
getRequest().setAttribute("tip", "服务器未知运行时异常");
log.error("运行时异常:", e);
return new ErrorResponseData(BizExceptionEnum.SERVER_ERROR.getCode(), BizExceptionEnum.SERVER_ERROR.getMessage());
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.aop;
import cn.stylefeng.guns.core.common.annotion.BussinessLog;
import cn.stylefeng.guns.core.log.LogManager;
import cn.stylefeng.guns.core.log.LogObjectHolder;
import cn.stylefeng.guns.core.log.factory.LogTaskFactory;
import cn.stylefeng.guns.core.shiro.ShiroKit;
import cn.stylefeng.guns.core.shiro.ShiroUser;
import cn.stylefeng.guns.core.util.Contrast;
import cn.stylefeng.roses.core.util.HttpContext;
import cn.stylefeng.guns.core.common.constant.dictmap.base.AbstractDictMap;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 日志记录
*
* @author fengshuonan
* @date 2016年12月6日 下午8:48:30
*/
@Aspect
@Component
public class LogAop {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Pointcut(value = "@annotation(cn.stylefeng.guns.core.common.annotion.BussinessLog)")
public void cutService() {
}
@Around("cutService()")
public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
//先执行业务
Object result = point.proceed();
try {
handle(point);
} catch (Exception e) {
log.error("日志记录出错!", e);
}
return result;
}
private void handle(ProceedingJoinPoint point) throws Exception {
//获取拦截的方法名
Signature sig = point.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Object target = point.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
String methodName = currentMethod.getName();
//如果当前用户未登录,不做日志
ShiroUser user = ShiroKit.getUser();
if (null == user) {
return;
}
//获取拦截方法的参数
String className = point.getTarget().getClass().getName();
Object[] params = point.getArgs();
//获取操作名称
BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);
String bussinessName = annotation.value();
String key = annotation.key();
Class dictClass = annotation.dict();
StringBuilder sb = new StringBuilder();
for (Object param : params) {
sb.append(param);
sb.append(" & ");
}
//如果涉及到修改,比对变化
String msg;
if (bussinessName.contains("修改") || bussinessName.contains("编辑")) {
Object obj1 = LogObjectHolder.me().get();
Map<String, String> obj2 = HttpContext.getRequestParameters();
msg = Contrast.contrastObj(dictClass, key, obj1, obj2);
} else {
Map<String, String> parameters = HttpContext.getRequestParameters();
AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();
msg = Contrast.parseMutiKey(dictMap,key,parameters);
}
LogManager.me().executeLog(LogTaskFactory.bussinessLog(user.getId(), bussinessName, className, methodName, msg));
}
}
\ No newline at end of file
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.aop;
import cn.stylefeng.guns.core.common.annotion.Permission;
import cn.stylefeng.guns.core.shiro.check.PermissionCheckManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.naming.NoPermissionException;
import java.lang.reflect.Method;
/**
* 权限检查的aop
*
* @author fengshuonan
* @date 2017-07-13 21:05
*/
@Aspect
@Component
@Order(200)
public class PermissionAop {
@Pointcut(value = "@annotation(cn.stylefeng.guns.core.common.annotion.Permission)")
private void cutPermission() {
}
@Around("cutPermission()")
public Object doPermission(ProceedingJoinPoint point) throws Throwable {
MethodSignature ms = (MethodSignature) point.getSignature();
Method method = ms.getMethod();
Permission permission = method.getAnnotation(Permission.class);
Object[] permissions = permission.value();
if (permissions.length == 0) {
//检查全体角色
boolean result = PermissionCheckManager.checkAll();
if (result) {
return point.proceed();
} else {
throw new NoPermissionException();
}
} else {
//检查指定角色
boolean result = PermissionCheckManager.check(permissions);
if (result) {
return point.proceed();
} else {
throw new NoPermissionException();
}
}
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.beetl;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.guns.core.tag.DictSelectorTag;
import cn.stylefeng.guns.core.util.KaptchaUtil;
import org.beetl.core.Context;
import org.beetl.core.Function;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
/**
* beetl拓展配置,绑定一些工具类,方便在模板中直接调用
*
* @author stylefeng
* @Date 2018/2/22 21:03
*/
public class BeetlConfiguration extends BeetlGroupUtilConfiguration {
@Autowired
private Environment env;
@Autowired
private DictSelectorTag dictSelectorTag;
@Override
public void initOther() {
groupTemplate.registerFunctionPackage("shiro", new ShiroExt());
groupTemplate.registerFunctionPackage("tool", new ToolUtil());
groupTemplate.registerFunctionPackage("kaptcha", new KaptchaUtil());
groupTemplate.registerTagFactory("dictSelector", () -> dictSelectorTag);
groupTemplate.registerFunction("env", new Function() {
@Override
public String call(Object[] paras, Context ctx) {
String key = (String) paras[0];
String value = env.getProperty(key);
if (value != null) {
return getStr(value);
}
if (paras.length == 2) {
return (String) paras[1];
}
return null;
}
String getStr(String str) {
try {
return new String(str.getBytes("iso8859-1"), StandardCharsets.UTF_8);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
});
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.beetl;
import cn.stylefeng.guns.core.shiro.ShiroUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
public class ShiroExt {
private static final String NAMES_DELIMETER = ",";
/**
* 获取当前 Subject
*
* @return Subject
*/
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
/**
* 获取封装的 ShiroUser
*
* @return ShiroUser
*/
public ShiroUser getUser() {
if (isGuest()) {
return null;
} else {
return (ShiroUser) getSubject().getPrincipals().getPrimaryPrincipal();
}
}
/**
* 验证当前用户是否属于该角色?,使用时与lacksRole 搭配使用
*
* @param roleName 角色名
* @return 属于该角色:true,否则false
*/
public boolean hasRole(String roleName) {
return getSubject() != null && roleName != null
&& roleName.length() > 0 && getSubject().hasRole(roleName);
}
/**
* 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。
*
* @param roleName 角色名
* @return 不属于该角色:true,否则false
*/
public boolean lacksRole(String roleName) {
return !hasRole(roleName);
}
/**
* 验证当前用户是否属于以下任意一个角色。
*
* @param roleNames 角色列表
* @return 属于:true,否则false
*/
public boolean hasAnyRoles(String roleNames) {
boolean hasAnyRole = false;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (subject.hasRole(role.trim())) {
hasAnyRole = true;
break;
}
}
}
return hasAnyRole;
}
/**
* 验证当前用户是否属于以下所有角色。
*
* @param roleNames 角色列表
* @return 属于:true,否则false
*/
public boolean hasAllRoles(String roleNames) {
boolean hasAllRole = true;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (!subject.hasRole(role.trim())) {
hasAllRole = false;
break;
}
}
}
return hasAllRole;
}
/**
* 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用
*
* @param permission 权限名
* @return 拥有权限:true,否则false
*/
public boolean hasPermission(String permission) {
return getSubject() != null && permission != null
&& permission.length() > 0
&& getSubject().isPermitted(permission);
}
/**
* 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。
*
* @param permission 权限名
* @return 拥有权限:true,否则false
*/
public boolean lacksPermission(String permission) {
return !hasPermission(permission);
}
/**
* 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。与notAuthenticated搭配使用
*
* @return 通过身份验证:true,否则false
*/
public boolean authenticated() {
return getSubject() != null && getSubject().isAuthenticated();
}
/**
* 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。。
*
* @return 没有通过身份验证:true,否则false
*/
public boolean notAuthenticated() {
return !authenticated();
}
/**
* 认证通过或已记住的用户。与guset搭配使用。
*
* @return 用户:true,否则 false
*/
public boolean isUser() {
return getSubject() != null && getSubject().getPrincipal() != null;
}
/**
* 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。用user搭配使用
*
* @return 访客:true,否则false
*/
public boolean isGuest() {
return !isUser();
}
/**
* 输出当前用户信息,通常为登录帐号信息。
*
* @return 当前用户信息
*/
public String principal() {
if (getSubject() != null) {
Object principal = getSubject().getPrincipal();
return principal.toString();
}
return "";
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.cache;
/**
* 缓存工厂基类
*/
public abstract class BaseCacheFactory implements ICache {
@SuppressWarnings("unchecked")
public <T> T get(String cacheName, Object key, ILoader iLoader) {
Object data = get(cacheName, key);
if (data == null) {
data = iLoader.load();
put(cacheName, key, data);
}
return (T) data;
}
@SuppressWarnings("unchecked")
public <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) {
Object data = get(cacheName, key);
if (data == null) {
try {
ILoader dataLoader = iLoaderClass.newInstance();
data = dataLoader.load();
put(cacheName, key, data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return (T) data;
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.cache;
import java.util.List;
/**
* 缓存工具类
*/
public class CacheKit {
private static ICache defaultCacheFactory = new EhcacheFactory();
public static void put(String cacheName, Object key, Object value) {
defaultCacheFactory.put(cacheName, key, value);
}
public static <T> T get(String cacheName, Object key) {
return defaultCacheFactory.get(cacheName, key);
}
@SuppressWarnings("rawtypes")
public static List getKeys(String cacheName) {
return defaultCacheFactory.getKeys(cacheName);
}
public static void remove(String cacheName, Object key) {
defaultCacheFactory.remove(cacheName, key);
}
public static void removeAll(String cacheName) {
defaultCacheFactory.removeAll(cacheName);
}
public static <T> T get(String cacheName, Object key, ILoader iLoader) {
return defaultCacheFactory.get(cacheName, key, iLoader);
}
public static <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) {
return defaultCacheFactory.get(cacheName, key, iLoaderClass);
}
}
/**
* Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.cache;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Ehcache缓存工厂
*/
public class EhcacheFactory extends BaseCacheFactory {
private static CacheManager cacheManager;
private static volatile Object locker = new Object();
private static final Logger log = LoggerFactory.getLogger(EhcacheFactory.class);
private static CacheManager getCacheManager() {
if (cacheManager == null) {
synchronized (EhcacheFactory.class) {
if (cacheManager == null) {
cacheManager = CacheManager.create();
}
}
}
return cacheManager;
}
static Cache getOrAddCache(String cacheName) {
CacheManager cacheManager = getCacheManager();
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
synchronized(locker) {
cache = cacheManager.getCache(cacheName);
if (cache == null) {
log.warn("无法找到缓存 [" + cacheName + "]的配置, 使用默认配置.");
cacheManager.addCacheIfAbsent(cacheName);
cache = cacheManager.getCache(cacheName);
log.debug("缓存 [" + cacheName + "] 启动.");
}
}
}
return cache;
}
public void put(String cacheName, Object key, Object value) {
getOrAddCache(cacheName).put(new Element(key, value));
}
@SuppressWarnings("unchecked")
public <T> T get(String cacheName, Object key) {
Element element = getOrAddCache(cacheName).get(key);
return element != null ? (T)element.getObjectValue() : null;
}
@SuppressWarnings("rawtypes")
public List getKeys(String cacheName) {
return getOrAddCache(cacheName).getKeys();
}
public void remove(String cacheName, Object key) {
getOrAddCache(cacheName).remove(key);
}
public void removeAll(String cacheName) {
getOrAddCache(cacheName).removeAll();
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.cache;
import java.util.List;
/**
* 通用缓存接口
*/
public interface ICache {
void put(String cacheName, Object key, Object value);
<T> T get(String cacheName, Object key);
@SuppressWarnings("rawtypes")
List getKeys(String cacheName);
void remove(String cacheName, Object key);
void removeAll(String cacheName);
<T> T get(String cacheName, Object key, ILoader iLoader);
<T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass);
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.cache;
/**
* 数据重载
*/
public interface ILoader {
Object load();
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.common.annotion;
import cn.stylefeng.guns.core.common.constant.dictmap.base.AbstractDictMap;
import cn.stylefeng.guns.core.common.constant.dictmap.base.SystemDict;
import java.lang.annotation.*;
/**
* 标记需要做业务日志的方法
*
* @author fengshuonan
* @date 2017-03-31 12:46
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BussinessLog {
/**
* 业务的名称,例如:"修改菜单"
*/
String value() default "";
/**
* 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"
*/
String key() default "id";
/**
* 字典(用于查找key的中文名称和字段的中文名称)
*/
Class<? extends AbstractDictMap> dict() default SystemDict.class;
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.common.annotion;
import java.lang.annotation.*;
/**
* 权限注解 用于检查权限 规定访问权限
*
* @example @Permission({role1,role2})
* @example @Permission
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Permission {
/**
* <p>角色英文名称</p>
* <p>使用注解时加上这个值表示限制只有某个角色的才可以访问对应的资源</p>
* <p>常用在某些资源限制只有超级管理员角色才可访问</p>
*/
String[] value() default {};
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.common.constant.cache;
/**
* 所有缓存名称的集合
*
* @author fengshuonan
* @date 2017-04-24 21:56
*/
public interface Cache {
/**
* 常量缓存
*/
String CONSTANT = "CONSTANT";
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.common.constant.cache;
/**
* 缓存标识前缀集合,常用在ConstantFactory类中
*
* @author fengshuonan
* @date 2017-04-25 9:37
*/
public interface CacheKey {
/**
* 角色名称(多个)
*/
String ROLES_NAME = "roles_name_";
/**
* 角色名称(单个)
*/
String SINGLE_ROLE_NAME = "single_role_name_";
/**
* 角色英文名称
*/
String SINGLE_ROLE_TIP = "single_role_tip_";
/**
* 部门名称
*/
String DEPT_NAME = "dept_name_";
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.common.constant.dictmap;
import cn.stylefeng.guns.core.common.constant.dictmap.base.AbstractDictMap;
/**
* 用于删除业务的字典
*
* @author fengshuonan
* @date 2017-05-06 15:01
*/
public class DeleteDict extends AbstractDictMap {
@Override
public void init() {
put("roleId","角色名称");
put("deptId", "部门名称");
put("menuId", "菜单名称");
put("dictId", "字典名称");
put("noticeId", "标题");
}
@Override
protected void initBeWrapped() {
putFieldWrapperMethodName("roleId","getCacheObject");
putFieldWrapperMethodName("deptId","getCacheObject");
putFieldWrapperMethodName("menuId","getCacheObject");
putFieldWrapperMethodName("dictId","getCacheObject");
putFieldWrapperMethodName("noticeId","getCacheObject");
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.common.constant.state;
/**
* 数据库排序
*
* @author fengshuonan
* @Date 2017年5月31日20:48:41
*/
public enum Order {
ASC("asc"), DESC("desc");
private String des;
Order(String des) {
this.des = des;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.log;
import java.util.TimerTask;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 日志管理器
*
* @author fengshuonan
* @date 2017-03-30 16:29
*/
public class LogManager {
//日志记录操作延时
private final int OPERATE_DELAY_TIME = 10;
//异步操作记录日志的线程池
private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
private LogManager() {
}
public static LogManager logManager = new LogManager();
public static LogManager me() {
return logManager;
}
public void executeLog(TimerTask task) {
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.log;
import cn.stylefeng.roses.core.util.SpringContextHolder;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import java.io.Serializable;
/**
* 被修改的bean临时存放的地方
*
* @author fengshuonan
* @date 2017-03-31 11:19
*/
@Component
@Scope(scopeName = WebApplicationContext.SCOPE_SESSION)
public class LogObjectHolder implements Serializable{
private Object object = null;
public void set(Object obj) {
this.object = obj;
}
public Object get() {
return object;
}
public static LogObjectHolder me(){
return SpringContextHolder.getBean(LogObjectHolder.class);
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.log.factory;
import cn.stylefeng.guns.core.common.constant.state.LogSucceed;
import cn.stylefeng.guns.core.common.constant.state.LogType;
import cn.stylefeng.guns.modular.system.model.LoginLog;
import cn.stylefeng.guns.modular.system.model.OperationLog;
import java.util.Date;
/**
* 日志对象创建工厂
*
* @author fengshuonan
* @date 2016年12月6日 下午9:18:27
*/
public class LogFactory {
/**
* 创建操作日志
*/
public static OperationLog createOperationLog(LogType logType, Integer userId, String bussinessName, String clazzName, String methodName, String msg, LogSucceed succeed) {
OperationLog operationLog = new OperationLog();
operationLog.setLogtype(logType.getMessage());
operationLog.setLogname(bussinessName);
operationLog.setUserid(userId);
operationLog.setClassname(clazzName);
operationLog.setMethod(methodName);
operationLog.setCreatetime(new Date());
operationLog.setSucceed(succeed.getMessage());
operationLog.setMessage(msg);
return operationLog;
}
/**
* 创建登录日志
*/
public static LoginLog createLoginLog(LogType logType, Integer userId, String msg, String ip) {
LoginLog loginLog = new LoginLog();
loginLog.setLogname(logType.getMessage());
loginLog.setUserid(userId);
loginLog.setCreatetime(new Date());
loginLog.setSucceed(LogSucceed.SUCCESS.getMessage());
loginLog.setIp(ip);
loginLog.setMessage(msg);
return loginLog;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.log.factory;
import cn.stylefeng.roses.core.util.SpringContextHolder;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.guns.core.common.constant.state.LogSucceed;
import cn.stylefeng.guns.core.common.constant.state.LogType;
import cn.stylefeng.guns.core.log.LogManager;
import cn.stylefeng.guns.modular.system.dao.LoginLogMapper;
import cn.stylefeng.guns.modular.system.dao.OperationLogMapper;
import cn.stylefeng.guns.modular.system.model.LoginLog;
import cn.stylefeng.guns.modular.system.model.OperationLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.TimerTask;
/**
* 日志操作任务创建工厂
*
* @author fengshuonan
* @date 2016年12月6日 下午9:18:27
*/
public class LogTaskFactory {
private static Logger logger = LoggerFactory.getLogger(LogManager.class);
private static LoginLogMapper loginLogMapper = SpringContextHolder.getBean(LoginLogMapper.class);
private static OperationLogMapper operationLogMapper = SpringContextHolder.getBean(OperationLogMapper.class);
public static TimerTask loginLog(final Integer userId, final String ip) {
return new TimerTask() {
@Override
public void run() {
try {
LoginLog loginLog = LogFactory.createLoginLog(LogType.LOGIN, userId, null, ip);
loginLogMapper.insert(loginLog);
} catch (Exception e) {
logger.error("创建登录日志异常!", e);
}
}
};
}
public static TimerTask loginLog(final String username, final String msg, final String ip) {
return new TimerTask() {
@Override
public void run() {
LoginLog loginLog = LogFactory.createLoginLog(
LogType.LOGIN_FAIL, null, "账号:" + username + "," + msg, ip);
try {
loginLogMapper.insert(loginLog);
} catch (Exception e) {
logger.error("创建登录失败异常!", e);
}
}
};
}
public static TimerTask exitLog(final Integer userId, final String ip) {
return new TimerTask() {
@Override
public void run() {
LoginLog loginLog = LogFactory.createLoginLog(LogType.EXIT, userId, null, ip);
try {
loginLogMapper.insert(loginLog);
} catch (Exception e) {
logger.error("创建退出日志异常!", e);
}
}
};
}
public static TimerTask bussinessLog(final Integer userId, final String bussinessName, final String clazzName, final String methodName, final String msg) {
return new TimerTask() {
@Override
public void run() {
OperationLog operationLog = LogFactory.createOperationLog(
LogType.BUSSINESS, userId, bussinessName, clazzName, methodName, msg, LogSucceed.SUCCESS);
try {
operationLogMapper.insert(operationLog);
} catch (Exception e) {
logger.error("创建业务日志异常!", e);
}
}
};
}
public static TimerTask exceptionLog(final Integer userId, final Exception exception) {
return new TimerTask() {
@Override
public void run() {
String msg = ToolUtil.getExceptionMsg(exception);
OperationLog operationLog = LogFactory.createOperationLog(
LogType.EXCEPTION, userId, "", null, null, msg, LogSucceed.FAIL);
try {
operationLogMapper.insert(operationLog);
} catch (Exception e) {
logger.error("创建异常日志异常!", e);
}
}
};
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.node;
import cn.stylefeng.roses.kernel.model.enums.YesOrNotEnum;
import java.util.*;
/**
* @author fengshuonan
* @Description 菜单的节点
* @date 2016年12月6日 上午11:34:17
*/
public class MenuNode implements Comparable {
/**
* 节点id
*/
private Long id;
/**
* 父节点
*/
private Long parentId;
/**
* 节点名称
*/
private String name;
/**
* 按钮级别
*/
private Integer levels;
/**
* 按钮级别
*/
private Integer ismenu;
/**
* 按钮的排序
*/
private Integer num;
/**
* 节点的url
*/
private String url;
/**
* 节点图标
*/
private String icon;
/**
* 子节点的集合
*/
private List<MenuNode> children;
/**
* 查询子节点时候的临时集合
*/
private List<MenuNode> linkedList = new ArrayList<MenuNode>();
public MenuNode() {
super();
}
public MenuNode(Long id, Long parentId) {
super();
this.id = id;
this.parentId = parentId;
}
public Integer getLevels() {
return levels;
}
public void setLevels(Integer levels) {
this.levels = levels;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public static MenuNode createRoot() {
return new MenuNode(0L, -1L);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public List<MenuNode> getChildren() {
return children;
}
public void setChildren(List<MenuNode> children) {
this.children = children;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public Integer getIsmenu() {
return ismenu;
}
public void setIsmenu(Integer ismenu) {
this.ismenu = ismenu;
}
@Override
public String toString() {
return "MenuNode{" +
"id=" + id +
", parentId=" + parentId +
", name='" + name + '\'' +
", levels=" + levels +
", num=" + num +
", url='" + url + '\'' +
", icon='" + icon + '\'' +
", children=" + children +
", linkedList=" + linkedList +
'}';
}
/**
* 重写排序比较接口,首先根据等级排序,然后更具排序字段排序
*
* @param o
* @return
*/
@Override
public int compareTo(Object o) {
MenuNode menuNode = (MenuNode) o;
Integer num = menuNode.getNum();
Integer levels = menuNode.getLevels();
if (num == null) {
num = 0;
}
if (levels == null) {
levels = 0;
}
if (this.levels.compareTo(levels) == 0) {
return this.num.compareTo(num);
} else {
return this.levels.compareTo(levels);
}
}
/**
* 构建页面菜单列表
*/
public static List<MenuNode> buildTitle(List<MenuNode> nodes) {
if (nodes.size() <= 0) {
return nodes;
}
//剔除非菜单
nodes.removeIf(node -> !node.getIsmenu().equals(YesOrNotEnum.Y.getCode()));
//对菜单排序,返回列表按菜单等级,序号的排序方式排列
Collections.sort(nodes);
return mergeList(nodes, nodes.get(nodes.size() - 1).getLevels(), null);
}
/**
* 递归合并数组为子数组,最后返回第一层
*
* @param menuList
* @param listMap
* @return
*/
private static List<MenuNode> mergeList(List<MenuNode> menuList, int rank, Map<Long, List<MenuNode>> listMap) {
//保存当次调用总共合并了多少元素
int n;
//保存当次调用总共合并出来的list
Map<Long, List<MenuNode>> currentMap = new HashMap<>();
//由于按等级从小到大排序,需要从后往前排序
//判断该节点是否属于当前循环的等级,不等于则跳出循环
for (n = menuList.size() - 1; n >=0&&menuList.get(n).getLevels() == rank; n--) {
//判断之前的调用是否有返回以该节点的id为key的map,有则设置为children列表。
if (listMap != null && listMap.get(menuList.get(n).getId()) != null) {
menuList.get(n).setChildren(listMap.get(menuList.get(n).getId()));
}
if (menuList.get(n).getParentId()!=null&&menuList.get(n).getParentId()!=0) {
//判断当前节点所属的pid是否已经创建了以该pid为key的键值对,没有则创建新的链表
currentMap.computeIfAbsent(menuList.get(n).getParentId(), k -> new LinkedList<>());
//将该节点插入到对应的list的头部
currentMap.get(menuList.get(n).getParentId()).add(0, menuList.get(n));
}
}
if (n <0) {
return menuList;
} else {
return mergeList(menuList.subList(0, n+1), menuList.get(n).getLevels(), currentMap);
}
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.node;
/**
* jquery ztree 插件的节点
*
* @author fengshuonan
* @date 2017年2月17日 下午8:25:14
*/
public class ZTreeNode {
private Long id; //节点id
private Long pId; //父节点id
private String name; //节点名称
private Boolean open; //是否打开节点
private Boolean checked; //是否被选中
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getpId() {
return pId;
}
public void setpId(Long pId) {
this.pId = pId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getOpen() {
return open;
}
public void setOpen(Boolean open) {
this.open = open;
}
public Boolean getIsOpen() {
return open;
}
public void setIsOpen(Boolean open) {
this.open = open;
}
public Boolean getChecked() {
return checked;
}
public void setChecked(Boolean checked) {
this.checked = checked;
}
public static ZTreeNode createParent() {
ZTreeNode zTreeNode = new ZTreeNode();
zTreeNode.setChecked(true);
zTreeNode.setId(0L);
zTreeNode.setName("顶级");
zTreeNode.setOpen(true);
zTreeNode.setpId(0L);
return zTreeNode;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.page;
import com.baomidou.mybatisplus.plugins.Page;
import java.util.List;
/**
* 分页结果的封装(for Bootstrap Table)
*
* @author fengshuonan
* @Date 2017年1月22日 下午11:06:41
*/
public class PageInfoBT<T> {
// 结果集
private List<T> rows;
// 总数
private long total;
public PageInfoBT(Page<T> page) {
this.rows = page.getRecords();
this.total = page.getTotal();
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.guns.core.shiro.factory.IShiro;
import cn.stylefeng.guns.core.shiro.factory.ShiroFactroy;
import cn.stylefeng.guns.modular.system.model.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ShiroDbRealm extends AuthorizingRealm {
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
throws AuthenticationException {
IShiro shiroFactory = ShiroFactroy.me();
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
User user = shiroFactory.user(token.getUsername());
ShiroUser shiroUser = shiroFactory.shiroUser(user);
return shiroFactory.info(shiroUser, user, super.getName());
}
/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
IShiro shiroFactory = ShiroFactroy.me();
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
List<Integer> roleList = shiroUser.getRoleList();
Set<String> permissionSet = new HashSet<>();
Set<String> roleNameSet = new HashSet<>();
for (Integer roleId : roleList) {
List<String> permissions = shiroFactory.findPermissionsByRoleId(roleId);
if (permissions != null) {
for (String permission : permissions) {
if (ToolUtil.isNotEmpty(permission)) {
permissionSet.add(permission);
}
}
}
String roleName = shiroFactory.findRoleNameByRoleId(roleId);
roleNameSet.add(roleName);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissionSet);
info.addRoles(roleNameSet);
return info;
}
/**
* 设置认证加密方式
*/
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();
md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);
md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);
super.setCredentialsMatcher(md5CredentialsMatcher);
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.guns.core.common.constant.Const;
import cn.stylefeng.guns.core.common.constant.factory.ConstantFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import java.util.List;
/**
* shiro工具类
*
* @author dafei, Chill Zhuang
*/
public class ShiroKit {
private static final String NAMES_DELIMETER = ",";
/**
* 加盐参数
*/
public final static String hashAlgorithmName = "MD5";
/**
* 循环次数
*/
public final static int hashIterations = 1024;
/**
* shiro密码加密工具类
*
* @param credentials 密码
* @param saltSource 密码盐
* @return
*/
public static String md5(String credentials, String saltSource) {
ByteSource salt = new Md5Hash(saltSource);
return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations).toString();
}
/**
* 获取随机盐值
* @param length
* @return
*/
public static String getRandomSalt(int length) {
return ToolUtil.getRandomString(length);
}
/**
* 获取当前 Subject
*
* @return Subject
*/
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
/**
* 获取封装的 ShiroUser
*
* @return ShiroUser
*/
public static ShiroUser getUser() {
if (isGuest()) {
return null;
} else {
return (ShiroUser) getSubject().getPrincipals().getPrimaryPrincipal();
}
}
/**
* 从shiro获取session
*
*/
public static Session getSession() {
return getSubject().getSession();
}
/**
* 获取shiro指定的sessionKey
*
*/
@SuppressWarnings("unchecked")
public static <T> T getSessionAttr(String key) {
Session session = getSession();
return session != null ? (T) session.getAttribute(key) : null;
}
/**
* 设置shiro指定的sessionKey
*
*/
public static void setSessionAttr(String key, Object value) {
Session session = getSession();
session.setAttribute(key, value);
}
/**
* 移除shiro指定的sessionKey
*/
public static void removeSessionAttr(String key) {
Session session = getSession();
if (session != null)
session.removeAttribute(key);
}
/**
* 验证当前用户是否属于该角色?,使用时与lacksRole 搭配使用
*
* @param roleName
* 角色名
* @return 属于该角色:true,否则false
*/
public static boolean hasRole(String roleName) {
return getSubject() != null && roleName != null
&& roleName.length() > 0 && getSubject().hasRole(roleName);
}
/**
* 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。
*
* @param roleName
* 角色名
* @return 不属于该角色:true,否则false
*/
public static boolean lacksRole(String roleName) {
return !hasRole(roleName);
}
/**
* 验证当前用户是否属于以下任意一个角色。
*
* @param roleNames
* 角色列表
* @return 属于:true,否则false
*/
public static boolean hasAnyRoles(String roleNames) {
boolean hasAnyRole = false;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (subject.hasRole(role.trim())) {
hasAnyRole = true;
break;
}
}
}
return hasAnyRole;
}
/**
* 验证当前用户是否属于以下所有角色。
*
* @param roleNames
* 角色列表
* @return 属于:true,否则false
*/
public static boolean hasAllRoles(String roleNames) {
boolean hasAllRole = true;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (!subject.hasRole(role.trim())) {
hasAllRole = false;
break;
}
}
}
return hasAllRole;
}
/**
* 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用
*
* @param permission
* 权限名
* @return 拥有权限:true,否则false
*/
public static boolean hasPermission(String permission) {
return getSubject() != null && permission != null
&& permission.length() > 0
&& getSubject().isPermitted(permission);
}
/**
* 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。
*
* @param permission
* 权限名
* @return 拥有权限:true,否则false
*/
public static boolean lacksPermission(String permission) {
return !hasPermission(permission);
}
/**
* 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。与notAuthenticated搭配使用
*
* @return 通过身份验证:true,否则false
*/
public static boolean isAuthenticated() {
return getSubject() != null && getSubject().isAuthenticated();
}
/**
* 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。。
*
* @return 没有通过身份验证:true,否则false
*/
public static boolean notAuthenticated() {
return !isAuthenticated();
}
/**
* 认证通过或已记住的用户。与guset搭配使用。
*
* @return 用户:true,否则 false
*/
public static boolean isUser() {
return getSubject() != null && getSubject().getPrincipal() != null;
}
/**
* 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。用user搭配使用
*
* @return 访客:true,否则false
*/
public static boolean isGuest() {
return !isUser();
}
/**
* 输出当前用户信息,通常为登录帐号信息。
*
* @return 当前用户信息
*/
public static String principal() {
if (getSubject() != null) {
Object principal = getSubject().getPrincipal();
return principal.toString();
}
return "";
}
/**
* 获取当前用户的部门数据范围的集合
*/
public static List<Integer> getDeptDataScope() {
Integer deptId = getUser().getDeptId();
List<Integer> subDeptIds = ConstantFactory.me().getSubDeptId(deptId);
subDeptIds.add(deptId);
return subDeptIds;
}
/**
* 判断当前用户是否是超级管理员
*/
public static boolean isAdmin() {
List<Integer> roleList = ShiroKit.getUser().getRoleList();
for (Integer integer : roleList) {
String singleRoleTip = ConstantFactory.me().getSingleRoleTip(integer);
if (singleRoleTip.equals(Const.ADMIN_NAME)) {
return true;
}
}
return false;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro;
import java.io.Serializable;
import java.util.List;
/**
* 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息
*
* @author fengshuonan
* @date 2016年12月5日 上午10:26:43
*/
public class ShiroUser implements Serializable {
private static final long serialVersionUID = 1L;
public Integer id; // 主键ID
public String account; // 账号
public String name; // 姓名
public Integer deptId; // 部门id
public List<Integer> roleList; // 角色集
public String deptName; // 部门名称
public List<String> roleNames; // 角色名称集
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public List<Integer> getRoleList() {
return roleList;
}
public void setRoleList(List<Integer> roleList) {
this.roleList = roleList;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<String> getRoleNames() {
return roleNames;
}
public void setRoleNames(List<String> roleNames) {
this.roleNames = roleNames;
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro.check;
/**
* 检查用接口
*/
public interface ICheck {
/**
* 检查当前登录用户是否拥有指定的角色访问当
*/
boolean check(Object[] permissions);
/**
* 检查当前登录用户是否拥有当前请求的servlet的权限
*/
boolean checkAll();
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro.check;
import cn.hutool.core.collection.CollectionUtil;
import cn.stylefeng.guns.core.shiro.ShiroKit;
import cn.stylefeng.guns.core.shiro.ShiroUser;
import cn.stylefeng.roses.core.util.HttpContext;
import cn.stylefeng.roses.core.util.SpringContextHolder;
import cn.stylefeng.guns.core.listener.ConfigListener;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
/**
* 权限自定义检查
*/
@Service
@DependsOn("springContextHolder")
@Transactional(readOnly = true)
public class PermissionCheckFactory implements ICheck {
public static ICheck me() {
return SpringContextHolder.getBean(ICheck.class);
}
@Override
public boolean check(Object[] permissions) {
ShiroUser user = ShiroKit.getUser();
if (null == user) {
return false;
}
ArrayList<Object> objects = CollectionUtil.newArrayList(permissions);
String join = CollectionUtil.join(objects, ",");
if (ShiroKit.hasAnyRoles(join)) {
return true;
}
return false;
}
@Override
public boolean checkAll() {
HttpServletRequest request = HttpContext.getRequest();
ShiroUser user = ShiroKit.getUser();
if (null == user) {
return false;
}
String requestURI = request.getRequestURI().replaceFirst(ConfigListener.getConf().get("contextPath"), "");
String[] str = requestURI.split("/");
if (str.length > 3) {
requestURI = "/" + str[1] + "/" + str[2];
}
if (ShiroKit.hasPermission(requestURI)) {
return true;
}
return false;
}
}
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro.check;
import cn.stylefeng.roses.core.util.SpringContextHolder;
/**
* 权限检查管理器(入口)
*/
public class PermissionCheckManager {
private final static PermissionCheckManager me = new PermissionCheckManager();
private ICheck defaultCheckFactory = SpringContextHolder.getBean(ICheck.class);
public static PermissionCheckManager me() {
return me;
}
private PermissionCheckManager() {
}
public PermissionCheckManager(ICheck checkFactory) {
this.defaultCheckFactory = checkFactory;
}
public void setDefaultCheckFactory(ICheck defaultCheckFactory) {
this.defaultCheckFactory = defaultCheckFactory;
}
public static boolean check(Object[] permissions) {
return me.defaultCheckFactory.check(permissions);
}
public static boolean checkAll() {
return me.defaultCheckFactory.checkAll();
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro.factory;
import cn.stylefeng.guns.core.shiro.ShiroUser;
import cn.stylefeng.guns.modular.system.model.User;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import java.util.List;
/**
* 定义shirorealm所需数据的接口
*
* @author fengshuonan
* @date 2016年12月5日 上午10:23:34
*/
public interface IShiro {
/**
* 根据账号获取登录用户
*
* @param account 账号
*/
User user(String account);
/**
* 根据系统用户获取Shiro的用户
*
* @param user 系统用户
*/
ShiroUser shiroUser(User user);
/**
* 获取权限列表通过角色id
*
* @param roleId 角色id
*/
List<String> findPermissionsByRoleId(Integer roleId);
/**
* 根据角色id获取角色名称
*
* @param roleId 角色id
*/
String findRoleNameByRoleId(Integer roleId);
/**
* 获取shiro的认证信息
*/
SimpleAuthenticationInfo info(ShiroUser shiroUser, User user, String realmName);
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.shiro.factory;
import cn.hutool.core.convert.Convert;
import cn.stylefeng.guns.core.shiro.ShiroUser;
import cn.stylefeng.roses.core.util.SpringContextHolder;
import cn.stylefeng.guns.core.common.constant.factory.ConstantFactory;
import cn.stylefeng.guns.core.common.constant.state.ManagerStatus;
import cn.stylefeng.guns.modular.system.dao.MenuMapper;
import cn.stylefeng.guns.modular.system.dao.UserMapper;
import cn.stylefeng.guns.modular.system.model.User;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@DependsOn("springContextHolder")
@Transactional(readOnly = true)
public class ShiroFactroy implements IShiro {
@Autowired
private UserMapper userMapper;
@Autowired
private MenuMapper menuMapper;
public static IShiro me() {
return SpringContextHolder.getBean(IShiro.class);
}
@Override
public User user(String account) {
User user = userMapper.getByAccount(account);
// 账号不存在
if (null == user) {
throw new CredentialsException();
}
// 账号被冻结
if (user.getStatus() != ManagerStatus.OK.getCode()) {
throw new LockedAccountException();
}
return user;
}
@Override
public ShiroUser shiroUser(User user) {
ShiroUser shiroUser = new ShiroUser();
shiroUser.setId(user.getId());
shiroUser.setAccount(user.getAccount());
shiroUser.setDeptId(user.getDeptid());
shiroUser.setDeptName(ConstantFactory.me().getDeptName(user.getDeptid()));
shiroUser.setName(user.getName());
Integer[] roleArray = Convert.toIntArray(user.getRoleid());
List<Integer> roleList = new ArrayList<Integer>();
List<String> roleNameList = new ArrayList<String>();
for (int roleId : roleArray) {
roleList.add(roleId);
roleNameList.add(ConstantFactory.me().getSingleRoleName(roleId));
}
shiroUser.setRoleList(roleList);
shiroUser.setRoleNames(roleNameList);
return shiroUser;
}
@Override
public List<String> findPermissionsByRoleId(Integer roleId) {
return menuMapper.getResUrlsByRoleId(roleId);
}
@Override
public String findRoleNameByRoleId(Integer roleId) {
return ConstantFactory.me().getSingleRoleTip(roleId);
}
@Override
public SimpleAuthenticationInfo info(ShiroUser shiroUser, User user, String realmName) {
String credentials = user.getPassword();
// 密码加盐处理
String source = user.getSalt();
ByteSource credentialsSalt = new Md5Hash(source);
return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, realmName);
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.tag;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import cn.stylefeng.guns.core.common.exception.BizExceptionEnum;
import cn.stylefeng.guns.modular.system.model.Dict;
import cn.stylefeng.guns.modular.system.service.IDictService;
import org.beetl.core.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 字典标签渲染
*
* @author zhangjiajia
* @Date 2018年6月4日17:33:32
*/
@Component
@Scope("prototype")
public class DictSelectorTag extends Tag {
@Autowired
IDictService iDictService;
@Override
public void render(){
//String tagName = (String) this.args[0];
Map attrs = (Map) args[1];
if(ToolUtil.isEmpty(attrs.get("code"))){
throw new ServiceException(BizExceptionEnum.ERROR_CODE_EMPTY);
}
//字典类型编码
String code = attrs.get("code").toString();
//控件显示类型select 选择框,radio 单选按钮,checkbox 多选按钮
String type = ToolUtil.isNotEmpty(attrs.get("type"))?attrs.get("type").toString():"select";
//开启多选
String multiple = ToolUtil.isNotEmpty(attrs.get("multiple"))?attrs.get("multiple").toString():"";
//字典名称
String label = ToolUtil.isNotEmpty(attrs.get("label"))?attrs.get("label").toString():"";
//提示
String placeholder = (ToolUtil.isNotEmpty(attrs.get("placeholder"))?attrs.get("placeholder").toString():"");
//宽度
String width = ToolUtil.isNotEmpty(attrs.get("width"))?attrs.get("width").toString():"248";
//默认值
String value = ToolUtil.isNotEmpty(attrs.get("value"))?attrs.get("value").toString():"";
//id
String id = ToolUtil.isNotEmpty(attrs.get("id"))?attrs.get("id").toString():"";
//name
String name = ToolUtil.isNotEmpty(attrs.get("name"))?attrs.get("name").toString():"";
//分割线
String underline = ToolUtil.isNotEmpty(attrs.get("underline"))?attrs.get("underline").toString():"";
//onchange事件
String onchange = ToolUtil.isNotEmpty(attrs.get("onchange"))?attrs.get("onchange").toString():"";
//readonly属性
String readonly = ToolUtil.isNotEmpty(attrs.get("readonly"))?attrs.get("readonly").toString():"";
//disabled属性
String disabled = ToolUtil.isNotEmpty(attrs.get("disabled"))?attrs.get("disabled").toString():"";
//searchnum 下拉选项数量达到多少启用搜索,默认10
int searchnum = ToolUtil.isNum(attrs.get("searchnum"))?Integer.parseInt(attrs.get("searchnum").toString()):10;
//根据code查询字典数据
List<Dict> list = iDictService.selectByParentCode(code);
StringBuffer html = new StringBuffer();
html.append("<div class=\"form-group\">\r\n");
html.append("<label class=\"col-sm-3 control-label\">"+label+"</label>\r\n");
html.append("<div class=\"col-sm-9\">\r\n");
//单选按钮
if("radio".equals(type)) {
list.forEach(obj->{
html.append("<label class=\"radio-inline i-checks\">\r\n<input type=\"radio\" ");
//判断控件是否禁用
if("true".equals(disabled)||"disabled".equals(disabled)) {
html.append("disabled ");
}else{
if(ToolUtil.isNotEmpty(name)){
html.append("name=\""+name+"\" ");
}
}
if("true".equals(readonly)||"disabled".equals(readonly)) {
html.append("disabled ");
}
if(ToolUtil.isNotEmpty(value)&&value.equals(obj.getCode())){
html.append("checked ");
}
html.append("value=\""+obj.getCode()+"\" >"+obj.getName()+"</label>\r\n");
});
//多选按钮
}else if("checkbox".equals(type)){
list.forEach(obj->{
html.append("<label class=\"checkbox-inline i-checks\">\r\n<input type=\"checkbox\" ");
//判断控件是否禁用
if("true".equals(disabled)||"disabled".equals(disabled)) {
html.append("disabled ");
}else{
if(ToolUtil.isNotEmpty(name)){
html.append("name=\""+name+"\" ");
}
}
if("true".equals(readonly)||"disabled".equals(readonly)) {
html.append("disabled ");
}
if(ToolUtil.isNotEmpty(value)&&value.equals(obj.getCode())){
html.append("checked ");
}
html.append("value=\""+obj.getCode()+"\" >"+obj.getName()+"</label>\r\n");
});
//默认select
}else{
//开启多选
if("true".equals(multiple)){
if(list.size()>=searchnum) {
html.append("<select multiple ");
}else{
html.append("<select multiple=\"multiple\" size=\"10\" ");
}
}else{
html.append("<select ");
}
//判断控件是否启用提示
if(ToolUtil.isNotEmpty(placeholder)){
html.append(" data-placeholder=\""+placeholder+"\" ");
}
//判断控件是否禁用
if("true".equals(disabled)||"disabled".equals(disabled)) {
html.append("disabled=\"disabled\" ");
}else{
//启用
if(ToolUtil.isNotEmpty(id)){
html.append("id=\""+id+"\" ");
}
if(ToolUtil.isNotEmpty(name)){
html.append("name=\""+name+"\" ");
}
}
//判断是否启用搜索框
//判断下拉数据,如果查询出来的条数达到启用搜索的数量就启用
if(list.size()>=searchnum){
html.append("class=\"form-control chosen-select\" style=\"width:"+width+"px\" tabindex=\"1\" \r\n");
} else{
html.append("class=\"form-control\" style=\"width:"+width+"px\" \r\n");
}
//判断控件是否只读
if("true".equals(readonly)||"readonly".equals(readonly)) {
if(list.size()>=searchnum) {
html.append("disabled=\"disabled\" ");
}else{
html.append("onfocus=\"this.defaultIndex=this.selectedIndex;\" onchange=\"this.selectedIndex=this.defaultIndex;\" ");
}
}
//判断是否绑定onchange事件
if(ToolUtil.isNotEmpty(onchange)){
html.append("onchange=\""+onchange+"($(this).children('option:selected').val())\" ");
}
html.append(">");
if(ToolUtil.isNotEmpty(placeholder)){
html.append("<option value=\"\">"+placeholder+"</option>\r\n");
}
//将查询出来的数据添加到select中
list.forEach(obj->{
if(ToolUtil.isNotEmpty(value)&&value.equals(obj.getCode())){
html.append("<option selected value=\""+obj.getCode()+"\">"+obj.getName()+"</option>\r\n");
}else{
html.append("<option value=\""+obj.getCode()+"\">"+obj.getName()+"</option>\r\n");
}
});
html.append("</select>\r\n");
}
html.append("</div>\r\n</div>\r\n");
//判断是否添加分割线
if(ToolUtil.isNotEmpty(underline) && "true".equals(underline)) {
html.append("<div class=\"hr-line-dashed\" ></div >\r\n");
}
try{
this.ctx.byteWriter.writeString(html.toString());
}catch (IOException e){
throw new RuntimeException("输出字典标签错误");
}
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.util;
import cn.stylefeng.roses.core.util.SpringContextHolder;
import cn.stylefeng.guns.config.properties.GunsProperties;
import cn.stylefeng.guns.core.common.constant.Const;
import cn.stylefeng.guns.core.node.MenuNode;
import java.util.ArrayList;
import java.util.List;
/**
* api接口文档显示过滤
*
* @author fengshuonan
* @date 2017-08-17 16:55
*/
public class ApiMenuFilter extends MenuNode {
public static List<MenuNode> build(List<MenuNode> nodes) {
//如果关闭了接口文档,则不显示接口文档菜单
GunsProperties gunsProperties = SpringContextHolder.getBean(GunsProperties.class);
if (!gunsProperties.getSwaggerOpen()) {
List<MenuNode> menuNodesCopy = new ArrayList<>();
for (MenuNode menuNode : nodes) {
if (Const.API_MENU_NAME.equals(menuNode.getName())) {
continue;
} else {
menuNodesCopy.add(menuNode);
}
}
nodes = menuNodesCopy;
}
return nodes;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.guns.core.common.constant.dictmap.base.AbstractDictMap;
import cn.stylefeng.guns.core.common.constant.dictmap.factory.DictFieldWarpperFactory;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
/**
* 对比两个对象的变化的工具类
*
* @author fengshuonan
* @Date 2017/3/31 10:36
*/
public class Contrast {
//记录每个修改字段的分隔符
public static final String separator = ";;;";
/**
* 比较两个对象,并返回不一致的信息
*
* @author stylefeng
* @Date 2017/5/9 19:34
*/
public static String contrastObj(Object pojo1, Object pojo2) {
String str = "";
try {
Class clazz = pojo1.getClass();
Field[] fields = pojo1.getClass().getDeclaredFields();
int i = 1;
for (Field field : fields) {
if ("serialVersionUID".equals(field.getName())) {
continue;
}
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
Method getMethod = pd.getReadMethod();
Object o1 = getMethod.invoke(pojo1);
Object o2 = getMethod.invoke(pojo2);
if (o1 == null || o2 == null) {
continue;
}
if (o1 instanceof Date) {
o1 = DateUtil.formatDate((Date) o1);
}
if (!o1.toString().equals(o2.toString())) {
if (i != 1) {
str += separator;
}
str += "字段名称" + field.getName() + ",旧值:" + o1 + ",新值:" + o2;
i++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
/**
* 比较两个对象pojo1和pojo2,并输出不一致信息
*
* @author stylefeng
* @Date 2017/5/9 19:34
*/
public static String contrastObj(Class dictClass, String key, Object pojo1, Map<String, String> pojo2) throws IllegalAccessException, InstantiationException {
AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();
String str = parseMutiKey(dictMap, key, pojo2) + separator;
try {
Class clazz = pojo1.getClass();
Field[] fields = pojo1.getClass().getDeclaredFields();
int i = 1;
for (Field field : fields) {
if ("serialVersionUID".equals(field.getName())) {
continue;
}
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
Method getMethod = pd.getReadMethod();
Object o1 = getMethod.invoke(pojo1);
Object o2 = pojo2.get(StrUtil.lowerFirst(getMethod.getName().substring(3)));
if (o1 == null || o2 == null) {
continue;
}
if (o1 instanceof Date) {
o1 = DateUtil.formatDate((Date) o1);
} else if (o1 instanceof Integer) {
o2 = Integer.parseInt(o2.toString());
}
if (!o1.toString().equals(o2.toString())) {
if (i != 1) {
str += separator;
}
String fieldName = dictMap.get(field.getName());
String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(field.getName());
if (fieldWarpperMethodName != null) {
Object o1Warpper = DictFieldWarpperFactory.createFieldWarpper(o1, fieldWarpperMethodName);
Object o2Warpper = DictFieldWarpperFactory.createFieldWarpper(o2, fieldWarpperMethodName);
str += "字段名称:" + fieldName + ",旧值:" + o1Warpper + ",新值:" + o2Warpper;
} else {
str += "字段名称:" + fieldName + ",旧值:" + o1 + ",新值:" + o2;
}
i++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
/**
* 比较两个对象pojo1和pojo2,并输出不一致信息
*
* @author stylefeng
* @Date 2017/5/9 19:34
*/
public static String contrastObjByName(Class dictClass, String key, Object pojo1, Map<String, String> pojo2) throws IllegalAccessException, InstantiationException {
AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();
String str = parseMutiKey(dictMap, key, pojo2) + separator;
try {
Class clazz = pojo1.getClass();
Field[] fields = pojo1.getClass().getDeclaredFields();
int i = 1;
for (Field field : fields) {
if ("serialVersionUID".equals(field.getName())) {
continue;
}
String prefix = "get";
int prefixLength = 3;
if (field.getType().getName().equals("java.lang.Boolean")) {
prefix = "is";
prefixLength = 2;
}
Method getMethod = null;
try {
getMethod = clazz.getDeclaredMethod(prefix + StrUtil.upperFirst(field.getName()));
} catch (java.lang.NoSuchMethodException e) {
System.err.println("this className:" + clazz.getName() + " is not methodName: " + e.getMessage());
continue;
}
Object o1 = getMethod.invoke(pojo1);
Object o2 = pojo2.get(StrUtil.lowerFirst(getMethod.getName().substring(prefixLength)));
if (o1 == null || o2 == null) {
continue;
}
if (o1 instanceof Date) {
o1 = DateUtil.formatDate((Date) o1);
} else if (o1 instanceof Integer) {
o2 = Integer.parseInt(o2.toString());
}
if (!o1.toString().equals(o2.toString())) {
if (i != 1) {
str += separator;
}
String fieldName = dictMap.get(field.getName());
String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(field.getName());
if (fieldWarpperMethodName != null) {
Object o1Warpper = DictFieldWarpperFactory.createFieldWarpper(o1, fieldWarpperMethodName);
Object o2Warpper = DictFieldWarpperFactory.createFieldWarpper(o2, fieldWarpperMethodName);
str += "字段名称:" + fieldName + ",旧值:" + o1Warpper + ",新值:" + o2Warpper;
} else {
str += "字段名称:" + fieldName + ",旧值:" + o1 + ",新值:" + o2;
}
i++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
/**
* 解析多个key(逗号隔开的)
*
* @author stylefeng
* @Date 2017/5/16 22:19
*/
public static String parseMutiKey(AbstractDictMap dictMap, String key, Map<String, String> requests) {
StringBuilder sb = new StringBuilder();
if (key.contains(",")) {
String[] keys = key.split(",");
for (String item : keys) {
String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(item);
String value = requests.get(item);
if (fieldWarpperMethodName != null) {
Object valueWarpper = DictFieldWarpperFactory.createFieldWarpper(value, fieldWarpperMethodName);
sb.append(dictMap.get(item) + "=" + valueWarpper + ",");
} else {
sb.append(dictMap.get(item) + "=" + value + ",");
}
}
return StrUtil.removeSuffix(sb.toString(), ",");
} else {
String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(key);
String value = requests.get(key);
if (fieldWarpperMethodName != null) {
Object valueWarpper = DictFieldWarpperFactory.createFieldWarpper(value, fieldWarpperMethodName);
sb.append(dictMap.get(key) + "=" + valueWarpper);
} else {
sb.append(dictMap.get(key) + "=" + value);
}
return sb.toString();
}
}
}
\ No newline at end of file
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.util;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.guns.core.common.constant.JwtConstants;
import io.jsonwebtoken.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* <p>jwt token工具类</p>
* <pre>
* jwt的claim里一般包含以下几种数据:
* 1. iss -- token的发行者
* 2. sub -- 该JWT所面向的用户
* 3. aud -- 接收该JWT的一方
* 4. exp -- token的失效时间
* 5. nbf -- 在此时间段之前,不会被处理
* 6. iat -- jwt发布时间
* 7. jti -- jwt唯一标识,防止重复使用
* </pre>
*
* @author fengshuonan
* @Date 2017/8/25 10:59
*/
public class JwtTokenUtil {
/**
* 获取用户名从token中
*/
public static String getUsernameFromToken(String token) {
return getClaimFromToken(token).getSubject();
}
/**
* 获取jwt发布时间
*/
public static Date getIssuedAtDateFromToken(String token) {
return getClaimFromToken(token).getIssuedAt();
}
/**
* 获取jwt失效时间
*/
public static Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token).getExpiration();
}
/**
* 获取jwt接收者
*/
public static String getAudienceFromToken(String token) {
return getClaimFromToken(token).getAudience();
}
/**
* 获取私有的jwt claim
*/
public static String getPrivateClaimFromToken(String token, String key) {
return getClaimFromToken(token).get(key).toString();
}
/**
* 获取jwt的payload部分
*/
public static Claims getClaimFromToken(String token) {
return Jwts.parser()
.setSigningKey(JwtConstants.SECRET)
.parseClaimsJws(token)
.getBody();
}
/**
* 解析token是否正确,不正确会报异常<br>
*/
public static void parseToken(String token) throws JwtException {
Jwts.parser().setSigningKey(JwtConstants.SECRET).parseClaimsJws(token).getBody();
}
/**
* <pre>
* 验证token是否失效
* true:过期 false:没过期
* </pre>
*/
public static Boolean isTokenExpired(String token) {
try {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
} catch (ExpiredJwtException expiredJwtException) {
return true;
}
}
/**
* 生成token(通过用户名和签名时候用的随机数)
*/
public static String generateToken(String userId) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userId);
}
/**
* 生成token
*/
private static String doGenerateToken(Map<String, Object> claims, String subject) {
final Date createdDate = new Date();
final Date expirationDate = new Date(createdDate.getTime() + JwtConstants.EXPIRATION * 1000);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, JwtConstants.SECRET)
.compact();
}
/**
* 获取混淆MD5签名用的随机字符串
*/
public static String getRandomKey() {
return ToolUtil.getRandomString(6);
}
}
\ No newline at end of file
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.core.util;
import cn.stylefeng.roses.core.util.SpringContextHolder;
import cn.stylefeng.guns.config.properties.GunsProperties;
/**
* 验证码工具类
*/
public class KaptchaUtil {
/**
* 获取验证码开关
*/
public static Boolean getKaptchaOnOff() {
return SpringContextHolder.getBean(GunsProperties.class).getKaptchaOpen();
}
}
\ No newline at end of file
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.guns.modular.system.service.INoticeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
import java.util.Map;
/**
* 总览信息
*
* @author fengshuonan
* @Date 2017年3月4日23:05:54
*/
@Controller
@RequestMapping("/blackboard")
public class BlackboardController extends BaseController {
@Autowired
private INoticeService noticeService;
/**
* 跳转到黑板
*/
@RequestMapping("")
public String blackboard(Model model) {
List<Map<String, Object>> notices = noticeService.list(null);
model.addAttribute("noticeList", notices);
return "/blackboard.html";
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.stylefeng.roses.core.util.FileUtil;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import cn.stylefeng.guns.config.properties.GunsProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* 验证码生成
*
* @author fengshuonan
* @date 2017-05-05 23:10
*/
@Controller
@RequestMapping("/kaptcha")
public class KaptchaController {
@Autowired
private GunsProperties gunsProperties;
@Autowired
private Producer producer;
/**
* 生成验证码
*/
@RequestMapping("")
public void index(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
response.setDateHeader("Expires", 0);
// Set standard HTTP/1.1 no-cache headers.
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
// Set standard HTTP/1.0 no-cache header.
response.setHeader("Pragma", "no-cache");
// return a jpeg
response.setContentType("image/jpeg");
// create the text for the image
String capText = producer.createText();
// store the text in the session
session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
// create the image with the text
BufferedImage bi = producer.createImage(capText);
ServletOutputStream out = null;
try {
out = response.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
// write the data out
try {
ImageIO.write(bi, "jpg", out);
} catch (IOException e) {
e.printStackTrace();
}
try {
try {
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 返回图片
*
* @author stylefeng
* @Date 2017/5/24 23:00
*/
@RequestMapping("/{pictureId}")
public void renderPicture(@PathVariable("pictureId") String pictureId, HttpServletResponse response) {
String path = gunsProperties.getFileUploadPath() + pictureId;
try {
byte[] bytes = FileUtil.toByteArray(path);
response.getOutputStream().write(bytes);
} catch (Exception e) {
//如果找不到图片就返回一个默认图片
try {
response.sendRedirect("/static/img/girl.gif");
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.stylefeng.guns.core.log.LogManager;
import cn.stylefeng.guns.core.log.factory.LogTaskFactory;
import cn.stylefeng.guns.core.node.MenuNode;
import cn.stylefeng.guns.core.shiro.ShiroKit;
import cn.stylefeng.guns.core.shiro.ShiroUser;
import cn.stylefeng.guns.core.util.ApiMenuFilter;
import cn.stylefeng.guns.core.util.KaptchaUtil;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.util.ToolUtil;
import com.google.code.kaptcha.Constants;
import cn.stylefeng.guns.core.common.exception.InvalidKaptchaException;
import cn.stylefeng.guns.modular.system.model.User;
import cn.stylefeng.guns.modular.system.service.IMenuService;
import cn.stylefeng.guns.modular.system.service.IUserService;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
import static cn.stylefeng.roses.core.util.HttpContext.getIp;
/**
* 登录控制器
*
* @author fengshuonan
* @Date 2017年1月10日 下午8:25:24
*/
@Controller
public class LoginController extends BaseController {
@Autowired
private IMenuService menuService;
@Autowired
private IUserService userService;
/**
* 跳转到主页
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Model model) {
//获取菜单列表
List<Integer> roleList = ShiroKit.getUser().getRoleList();
if (roleList == null || roleList.size() == 0) {
ShiroKit.getSubject().logout();
model.addAttribute("tips", "该用户没有角色,无法登陆");
return "/login.html";
}
List<MenuNode> menus = menuService.getMenusByRoleIds(roleList);
List<MenuNode> titles = MenuNode.buildTitle(menus);
titles = ApiMenuFilter.build(titles);
model.addAttribute("titles", titles);
//获取用户头像
Integer id = ShiroKit.getUser().getId();
User user = userService.selectById(id);
String avatar = user.getAvatar();
model.addAttribute("avatar", avatar);
return "/index.html";
}
/**
* 跳转到登录页面
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
if (ShiroKit.isAuthenticated() || ShiroKit.getUser() != null) {
return REDIRECT + "/";
} else {
return "/login.html";
}
}
/**
* 点击登录执行的动作
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginVali() {
String username = super.getPara("username").trim();
String password = super.getPara("password").trim();
String remember = super.getPara("remember");
//验证验证码是否正确
if (KaptchaUtil.getKaptchaOnOff()) {
String kaptcha = super.getPara("kaptcha").trim();
String code = (String) super.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
if (ToolUtil.isEmpty(kaptcha) || !kaptcha.equalsIgnoreCase(code)) {
throw new InvalidKaptchaException();
}
}
Subject currentUser = ShiroKit.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray());
if ("on".equals(remember)) {
token.setRememberMe(true);
} else {
token.setRememberMe(false);
}
currentUser.login(token);
ShiroUser shiroUser = ShiroKit.getUser();
super.getSession().setAttribute("shiroUser", shiroUser);
super.getSession().setAttribute("username", shiroUser.getAccount());
LogManager.me().executeLog(LogTaskFactory.loginLog(shiroUser.getId(), getIp()));
ShiroKit.getSession().setAttribute("sessionFlag", true);
return REDIRECT + "/";
}
/**
* 退出登录
*/
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logOut() {
LogManager.me().executeLog(LogTaskFactory.exitLog(ShiroKit.getUser().getId(), getIp()));
ShiroKit.getSubject().logout();
deleteAllCookie();
return REDIRECT + "/login";
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.stylefeng.guns.core.common.annotion.BussinessLog;
import cn.stylefeng.guns.core.common.annotion.Permission;
import cn.stylefeng.guns.core.page.PageInfoBT;
import cn.stylefeng.roses.core.base.controller.BaseController;
import com.baomidou.mybatisplus.mapper.SqlRunner;
import com.baomidou.mybatisplus.plugins.Page;
import cn.stylefeng.guns.core.common.constant.Const;
import cn.stylefeng.guns.core.common.constant.factory.PageFactory;
import cn.stylefeng.guns.modular.system.model.LoginLog;
import cn.stylefeng.guns.modular.system.service.ILoginLogService;
import cn.stylefeng.guns.modular.system.warpper.LogWarpper;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;
/**
* 日志管理的控制器
*
* @author fengshuonan
* @Date 2017年4月5日 19:45:36
*/
@Controller
@RequestMapping("/loginLog")
public class LoginLogController extends BaseController {
private static String PREFIX = "/system/log/";
@Autowired
private ILoginLogService loginLogService;
/**
* 跳转到日志管理的首页
*/
@RequestMapping("")
public String index() {
return PREFIX + "login_log.html";
}
/**
* 查询登录日志列表
*/
@RequestMapping("/list")
@Permission(Const.ADMIN_NAME)
@ResponseBody
public Object list(@RequestParam(required = false) String beginTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String logName) {
Page<LoginLog> page = new PageFactory<LoginLog>().defaultPage();
List<Map<String, Object>> result = loginLogService.getLoginLogs(page, beginTime, endTime, logName, page.getOrderByField(), page.isAsc());
page.setRecords(new LogWarpper(result).wrap());
return new PageInfoBT<>(page);
}
/**
* 清空日志
*/
@BussinessLog("清空登录日志")
@RequestMapping("/delLoginLog")
@Permission(Const.ADMIN_NAME)
@ResponseBody
public Object delLog() {
SqlRunner.db().delete("delete from sys_login_log");
return SUCCESS_TIP;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.stylefeng.guns.core.common.annotion.BussinessLog;
import cn.stylefeng.guns.core.common.annotion.Permission;
import cn.stylefeng.guns.core.log.LogObjectHolder;
import cn.stylefeng.guns.core.node.ZTreeNode;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import cn.stylefeng.guns.core.common.constant.Const;
import cn.stylefeng.guns.core.common.constant.dictmap.MenuDict;
import cn.stylefeng.guns.core.common.constant.factory.ConstantFactory;
import cn.stylefeng.guns.core.common.constant.state.MenuStatus;
import cn.stylefeng.guns.core.common.exception.BizExceptionEnum;
import cn.stylefeng.guns.modular.system.model.Menu;
import cn.stylefeng.guns.modular.system.service.IMenuService;
import cn.stylefeng.guns.modular.system.warpper.MenuWarpper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 菜单控制器
*
* @author fengshuonan
* @Date 2017年2月12日21:59:14
*/
@Controller
@RequestMapping("/menu")
public class MenuController extends BaseController {
private static String PREFIX = "/system/menu/";
@Autowired
private IMenuService menuService;
/**
* 跳转到菜单列表列表页面
*/
@RequestMapping("")
public String index() {
return PREFIX + "menu.html";
}
/**
* 跳转到菜单列表列表页面
*/
@RequestMapping(value = "/menu_add")
public String menuAdd() {
return PREFIX + "menu_add.html";
}
/**
* 跳转到菜单详情列表页面
*/
@Permission(Const.ADMIN_NAME)
@RequestMapping(value = "/menu_edit/{menuId}")
public String menuEdit(@PathVariable Long menuId, Model model) {
if (ToolUtil.isEmpty(menuId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
Menu menu = this.menuService.selectById(menuId);
//获取父级菜单的id
Menu temp = new Menu();
temp.setCode(menu.getPcode());
Menu pMenu = this.menuService.selectOne(new EntityWrapper<>(temp));
//如果父级是顶级菜单
if (pMenu == null) {
menu.setPcode("0");
} else {
//设置父级菜单的code为父级菜单的id
menu.setPcode(String.valueOf(pMenu.getId()));
}
Map<String, Object> menuMap = BeanUtil.beanToMap(menu);
menuMap.put("pcodeName", ConstantFactory.me().getMenuNameByCode(temp.getCode()));
model.addAttribute("menu", menuMap);
LogObjectHolder.me().set(menu);
return PREFIX + "menu_edit.html";
}
/**
* 修该菜单
*/
@Permission(Const.ADMIN_NAME)
@RequestMapping(value = "/edit")
@BussinessLog(value = "修改菜单", key = "name", dict = MenuDict.class)
@ResponseBody
public ResponseData edit(@Valid Menu menu, BindingResult result) {
if (result.hasErrors()) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
//设置父级菜单编号
menuSetPcode(menu);
this.menuService.updateById(menu);
return SUCCESS_TIP;
}
/**
* 获取菜单列表
*/
@Permission(Const.ADMIN_NAME)
@RequestMapping(value = "/list")
@ResponseBody
public Object list(@RequestParam(required = false) String menuName, @RequestParam(required = false) String level) {
List<Map<String, Object>> menus = this.menuService.selectMenus(menuName, level);
return super.warpObject(new MenuWarpper(menus));
}
/**
* 新增菜单
*/
@Permission(Const.ADMIN_NAME)
@RequestMapping(value = "/add")
@BussinessLog(value = "菜单新增", key = "name", dict = MenuDict.class)
@ResponseBody
public ResponseData add(@Valid Menu menu, BindingResult result) {
if (result.hasErrors()) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
//判断是否存在该编号
String existedMenuName = ConstantFactory.me().getMenuNameByCode(menu.getCode());
if (ToolUtil.isNotEmpty(existedMenuName)) {
throw new ServiceException(BizExceptionEnum.EXISTED_THE_MENU);
}
//设置父级菜单编号
menuSetPcode(menu);
menu.setStatus(MenuStatus.ENABLE.getCode());
this.menuService.insert(menu);
return SUCCESS_TIP;
}
/**
* 删除菜单
*/
@Permission(Const.ADMIN_NAME)
@RequestMapping(value = "/remove")
@BussinessLog(value = "删除菜单", key = "menuId", dict = MenuDict.class)
@ResponseBody
public ResponseData remove(@RequestParam Long menuId) {
if (ToolUtil.isEmpty(menuId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
//缓存菜单的名称
LogObjectHolder.me().set(ConstantFactory.me().getMenuName(menuId));
this.menuService.delMenuContainSubMenus(menuId);
return SUCCESS_TIP;
}
/**
* 查看菜单
*/
@RequestMapping(value = "/view/{menuId}")
@ResponseBody
public ResponseData view(@PathVariable Long menuId) {
if (ToolUtil.isEmpty(menuId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
this.menuService.selectById(menuId);
return SUCCESS_TIP;
}
/**
* 获取菜单列表(首页用)
*/
@RequestMapping(value = "/menuTreeList")
@ResponseBody
public List<ZTreeNode> menuTreeList() {
return this.menuService.menuTreeList();
}
/**
* 获取菜单列表(选择父级菜单用)
*/
@RequestMapping(value = "/selectMenuTreeList")
@ResponseBody
public List<ZTreeNode> selectMenuTreeList() {
List<ZTreeNode> roleTreeList = this.menuService.menuTreeList();
roleTreeList.add(ZTreeNode.createParent());
return roleTreeList;
}
/**
* 获取角色列表
*/
@RequestMapping(value = "/menuTreeListByRoleId/{roleId}")
@ResponseBody
public List<ZTreeNode> menuTreeListByRoleId(@PathVariable Integer roleId) {
List<Long> menuIds = this.menuService.getMenuIdsByRoleId(roleId);
if (ToolUtil.isEmpty(menuIds)) {
return this.menuService.menuTreeList();
} else {
return this.menuService.menuTreeListByMenuIds(menuIds);
}
}
/**
* 根据请求的父级菜单编号设置pcode和层级
*/
private void menuSetPcode(@Valid Menu menu) {
if (ToolUtil.isEmpty(menu.getPcode()) || menu.getPcode().equals("0")) {
menu.setPcode("0");
menu.setPcodes("[0],");
menu.setLevels(1);
} else {
long code = Long.parseLong(menu.getPcode());
Menu pMenu = menuService.selectById(code);
Integer pLevels = pMenu.getLevels();
menu.setPcode(pMenu.getCode());
//如果编号和父编号一致会导致无限递归
if (menu.getCode().equals(menu.getPcode())) {
throw new ServiceException(BizExceptionEnum.MENU_PCODE_COINCIDENCE);
}
menu.setLevels(pLevels + 1);
menu.setPcodes(pMenu.getPcodes() + "[" + pMenu.getCode() + "],");
}
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.stylefeng.guns.core.common.annotion.BussinessLog;
import cn.stylefeng.guns.core.log.LogObjectHolder;
import cn.stylefeng.guns.core.shiro.ShiroKit;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import cn.stylefeng.guns.core.common.constant.dictmap.NoticeMap;
import cn.stylefeng.guns.core.common.constant.factory.ConstantFactory;
import cn.stylefeng.guns.core.common.exception.BizExceptionEnum;
import cn.stylefeng.guns.modular.system.model.Notice;
import cn.stylefeng.guns.modular.system.service.INoticeService;
import cn.stylefeng.guns.modular.system.warpper.NoticeWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 通知控制器
*
* @author fengshuonan
* @Date 2017-05-09 23:02:21
*/
@Controller
@RequestMapping("/notice")
public class NoticeController extends BaseController {
private String PREFIX = "/system/notice/";
@Autowired
private INoticeService noticeService;
/**
* 跳转到通知列表首页
*/
@RequestMapping("")
public String index() {
return PREFIX + "notice.html";
}
/**
* 跳转到添加通知
*/
@RequestMapping("/notice_add")
public String noticeAdd() {
return PREFIX + "notice_add.html";
}
/**
* 跳转到修改通知
*/
@RequestMapping("/notice_update/{noticeId}")
public String noticeUpdate(@PathVariable Integer noticeId, Model model) {
Notice notice = this.noticeService.selectById(noticeId);
model.addAttribute("notice",notice);
LogObjectHolder.me().set(notice);
return PREFIX + "notice_edit.html";
}
/**
* 跳转到首页通知
*/
@RequestMapping("/hello")
public String hello() {
List<Map<String, Object>> notices = noticeService.list(null);
super.setAttr("noticeList",notices);
return "/blackboard.html";
}
/**
* 获取通知列表
*/
@RequestMapping(value = "/list")
@ResponseBody
public Object list(String condition) {
List<Map<String, Object>> list = this.noticeService.list(condition);
return super.warpObject(new NoticeWrapper(list));
}
/**
* 新增通知
*/
@RequestMapping(value = "/add")
@ResponseBody
@BussinessLog(value = "新增通知",key = "title",dict = NoticeMap.class)
public Object add(Notice notice) {
if (ToolUtil.isOneEmpty(notice, notice.getTitle(), notice.getContent())) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
notice.setCreater(ShiroKit.getUser().getId());
notice.setCreatetime(new Date());
notice.insert();
return SUCCESS_TIP;
}
/**
* 删除通知
*/
@RequestMapping(value = "/delete")
@ResponseBody
@BussinessLog(value = "删除通知",key = "noticeId",dict = NoticeMap.class)
public Object delete(@RequestParam Integer noticeId) {
//缓存通知名称
LogObjectHolder.me().set(ConstantFactory.me().getNoticeTitle(noticeId));
this.noticeService.deleteById(noticeId);
return SUCCESS_TIP;
}
/**
* 修改通知
*/
@RequestMapping(value = "/update")
@ResponseBody
@BussinessLog(value = "修改通知",key = "title",dict = NoticeMap.class)
public Object update(Notice notice) {
if (ToolUtil.isOneEmpty(notice, notice.getId(), notice.getTitle(), notice.getContent())) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
Notice old = this.noticeService.selectById(notice.getId());
old.setTitle(notice.getTitle());
old.setContent(notice.getContent());
old.updateById();
return SUCCESS_TIP;
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.system.controller;
import cn.stylefeng.guns.core.cache.CacheKit;
import cn.stylefeng.guns.core.common.annotion.BussinessLog;
import cn.stylefeng.guns.core.common.annotion.Permission;
import cn.stylefeng.guns.core.common.constant.cache.Cache;
import cn.stylefeng.guns.core.log.LogObjectHolder;
import cn.stylefeng.guns.core.node.ZTreeNode;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import cn.stylefeng.guns.core.common.constant.Const;
import cn.stylefeng.guns.core.common.constant.dictmap.RoleDict;
import cn.stylefeng.guns.core.common.constant.factory.ConstantFactory;
import cn.stylefeng.guns.core.common.exception.BizExceptionEnum;
import cn.stylefeng.guns.modular.system.model.Role;
import cn.stylefeng.guns.modular.system.model.User;
import cn.stylefeng.guns.modular.system.service.IRoleService;
import cn.stylefeng.guns.modular.system.service.IUserService;
import cn.stylefeng.guns.modular.system.warpper.RoleWarpper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 角色控制器
*
* @author fengshuonan
* @Date 2017年2月12日21:59:14
*/
@Controller
@RequestMapping("/role")
public class RoleController extends BaseController {
private static String PREFIX = "/system/role";
@Autowired
private IUserService userService;
@Autowired
private IRoleService roleService;
/**
* 跳转到角色列表页面
*/
@RequestMapping("")
public String index() {
return PREFIX + "/role.html";
}
/**
* 跳转到添加角色
*/
@RequestMapping(value = "/role_add")
public String roleAdd() {
return PREFIX + "/role_add.html";
}
/**
* 跳转到修改角色
*/
@Permission
@RequestMapping(value = "/role_edit/{roleId}")
public String roleEdit(@PathVariable Integer roleId, Model model) {
if (ToolUtil.isEmpty(roleId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
Role role = this.roleService.selectById(roleId);
model.addAttribute(role);
model.addAttribute("pName", ConstantFactory.me().getSingleRoleName(role.getPid()));
model.addAttribute("deptName", ConstantFactory.me().getDeptName(role.getDeptid()));
LogObjectHolder.me().set(role);
return PREFIX + "/role_edit.html";
}
/**
* 跳转到角色分配
*/
@Permission
@RequestMapping(value = "/role_assign/{roleId}")
public String roleAssign(@PathVariable("roleId") Integer roleId, Model model) {
if (ToolUtil.isEmpty(roleId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
model.addAttribute("roleId", roleId);
model.addAttribute("roleName", ConstantFactory.me().getSingleRoleName(roleId));
return PREFIX + "/role_assign.html";
}
/**
* 获取角色列表
*/
@Permission
@RequestMapping(value = "/list")
@ResponseBody
public Object list(@RequestParam(required = false) String roleName) {
List<Map<String, Object>> roles = this.roleService.selectRoles(super.getPara("roleName"));
return super.warpObject(new RoleWarpper(roles));
}
/**
* 角色新增
*/
@RequestMapping(value = "/add")
@BussinessLog(value = "添加角色", key = "name", dict = RoleDict.class)
@Permission(Const.ADMIN_NAME)
@ResponseBody
public ResponseData add(@Valid Role role, BindingResult result) {
if (result.hasErrors()) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
role.setId(null);
this.roleService.insert(role);
return SUCCESS_TIP;
}
/**
* 角色修改
*/
@RequestMapping(value = "/edit")
@BussinessLog(value = "修改角色", key = "name", dict = RoleDict.class)
@Permission(Const.ADMIN_NAME)
@ResponseBody
public ResponseData edit(@Valid Role role, BindingResult result) {
if (result.hasErrors()) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
this.roleService.updateById(role);
//删除缓存
CacheKit.removeAll(Cache.CONSTANT);
return SUCCESS_TIP;
}
/**
* 删除角色
*/
@RequestMapping(value = "/remove")
@BussinessLog(value = "删除角色", key = "roleId", dict = RoleDict.class)
@Permission(Const.ADMIN_NAME)
@ResponseBody
public ResponseData remove(@RequestParam Integer roleId) {
if (ToolUtil.isEmpty(roleId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
//不能删除超级管理员角色
if (roleId.equals(Const.ADMIN_ROLE_ID)) {
throw new ServiceException(BizExceptionEnum.CANT_DELETE_ADMIN);
}
//缓存被删除的角色名称
LogObjectHolder.me().set(ConstantFactory.me().getSingleRoleName(roleId));
this.roleService.delRoleById(roleId);
//删除缓存
CacheKit.removeAll(Cache.CONSTANT);
return SUCCESS_TIP;
}
/**
* 查看角色
*/
@RequestMapping(value = "/view/{roleId}")
@ResponseBody
public ResponseData view(@PathVariable Integer roleId) {
if (ToolUtil.isEmpty(roleId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
this.roleService.selectById(roleId);
return SUCCESS_TIP;
}
/**
* 配置权限
*/
@RequestMapping("/setAuthority")
@BussinessLog(value = "配置权限", key = "roleId,ids", dict = RoleDict.class)
@Permission(Const.ADMIN_NAME)
@ResponseBody
public ResponseData setAuthority(@RequestParam("roleId") Integer roleId, @RequestParam("ids") String ids) {
if (ToolUtil.isOneEmpty(roleId)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
this.roleService.setAuthority(roleId, ids);
return SUCCESS_TIP;
}
/**
* 获取角色列表
*/
@RequestMapping(value = "/roleTreeList")
@ResponseBody
public List<ZTreeNode> roleTreeList() {
List<ZTreeNode> roleTreeList = this.roleService.roleTreeList();
roleTreeList.add(ZTreeNode.createParent());
return roleTreeList;
}
/**
* 获取角色列表
*/
@RequestMapping(value = "/roleTreeListByUserId/{userId}")
@ResponseBody
public List<ZTreeNode> roleTreeListByUserId(@PathVariable Integer userId) {
User theUser = this.userService.selectById(userId);
String roleid = theUser.getRoleid();
if (ToolUtil.isEmpty(roleid)) {
return this.roleService.roleTreeList();
} else {
String[] strArray = roleid.split(",");
return this.roleService.roleTreeListByRoleId(strArray);
}
}
}
package cn.stylefeng.guns.modular.system.model;
import com.baomidou.mybatisplus.activerecord.Model;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import java.io.Serializable;
/**
* <p>
* 角色和菜单关联表
* </p>
*
* @author stylefeng
* @since 2017-07-11
*/
@TableName("sys_relation")
public class Relation extends Model<Relation> {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 菜单id
*/
private Long menuid;
/**
* 角色id
*/
private Integer roleid;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Long getMenuid() {
return menuid;
}
public void setMenuid(Long menuid) {
this.menuid = menuid;
}
public Integer getRoleid() {
return roleid;
}
public void setRoleid(Integer roleid) {
this.roleid = roleid;
}
@Override
protected Serializable pkVal() {
return this.id;
}
@Override
public String toString() {
return "Relation{" +
"id=" + id +
", menuid=" + menuid +
", roleid=" + roleid +
"}";
}
}
package cn.stylefeng.guns.base;
import cn.stylefeng.guns.GunsApplication;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
/**
* 基础测试类
*
* @author stylefeng
* @Date 2017/5/21 16:10
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = GunsApplication.class)
@WebAppConfiguration
//@Transactional //打开的话测试之后数据可自动回滚
public class BaseJunit {
@Autowired
WebApplicationContext webApplicationContext;
protected MockMvc mockMvc;
@Before
public void setupMockMvc(){
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Before
public void initDatabase(){
}
}
package cn.stylefeng.guns.multi.entity;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.enums.IdType;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author fengshuonan
* @since 2018-07-10
*/
public class Test implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "aaa", type = IdType.AUTO)
private Integer aaa;
private String bbb;
public Integer getAaa() {
return aaa;
}
public void setAaa(Integer aaa) {
this.aaa = aaa;
}
public String getBbb() {
return bbb;
}
public void setBbb(String bbb) {
this.bbb = bbb;
}
@Override
public String toString() {
return "Test{" +
"aaa=" + aaa +
", bbb=" + bbb +
"}";
}
}
package cn.stylefeng.guns.multi.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import cn.stylefeng.guns.multi.entity.Test;
/**
* <p>
* Mapper 接口
* </p>
*
* @author fengshuonan
* @since 2018-07-10
*/
public interface TestMapper extends BaseMapper<Test> {
}
<?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="share.example.modular.mapper.TestMapper">
<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.stylefeng.guns.multi.entity.Test">
<id column="aaa" property="aaa" />
<result column="bbb" property="bbb" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
aaa, bbb
</sql>
</mapper>
package cn.stylefeng.guns.multi.service;
/**
* <p>
* 服务类
* </p>
*
* @author fengshuonan
* @since 2018-07-10
*/
public interface TestService {
/**
* 测试多数据源的业务
*
* @author stylefeng
* @Date 2017/6/23 23:02
*/
void testBiz();
/**
* 测试多数据源的业务
*
* @author stylefeng
* @Date 2017/6/23 23:02
*/
void testGuns();
/**
* 测试多数据源的业务
*
* @author stylefeng
* @Date 2017/6/23 23:02
*/
void testAll();
}
package cn.stylefeng.guns.multi.service.impl;
import cn.stylefeng.roses.core.mutidatasource.annotion.DataSource;
import cn.stylefeng.guns.core.common.constant.DatasourceEnum;
import cn.stylefeng.guns.multi.entity.Test;
import cn.stylefeng.guns.multi.mapper.TestMapper;
import cn.stylefeng.guns.multi.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* <p>
* 服务实现类
* </p>
*
* @author fengshuonan
* @since 2018-07-10
*/
@Service
public class TestServiceImpl implements TestService {
@Autowired
private TestMapper testMapper;
@Override
@DataSource(name = DatasourceEnum.DATA_SOURCE_BIZ)
@Transactional
public void testBiz() {
Test test = new Test();
test.setBbb("bizTest");
testMapper.insert(test);
}
@Override
@DataSource(name = DatasourceEnum.DATA_SOURCE_GUNS)
@Transactional
public void testGuns() {
Test test = new Test();
test.setBbb("gunsTest");
testMapper.insert(test);
}
@Override
@Transactional
public void testAll() {
testBiz();
testGuns();
//int i = 1 / 0;
}
}
package cn.stylefeng.guns.multi.test;
import cn.stylefeng.guns.multi.service.TestService;
import cn.stylefeng.guns.base.BaseJunit;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 业务测试
*
* @author fengshuonan
* @date 2017-06-23 23:12
*/
public class BizTest extends BaseJunit {
@Autowired
TestService testService;
@Test
public void test() {
testService.testGuns();
testService.testBiz();
//testService.testAll();
}
}
package cn.stylefeng.guns.shiro;
import org.springframework.util.Base64Utils;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Base64Test {
/**
* Shiro 记住密码采用的是AES加密,AES key length 需要是16位,该方法生成16位的key
*/
public static void main(String[] args) {
String keyStr = "guns";
byte[] keys;
try {
keys = keyStr.getBytes("UTF-8");
System.out.println(Base64Utils.encodeToString(Arrays.copyOf(keys, 16)));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
package cn.stylefeng.guns.system;
import cn.stylefeng.guns.base.BaseJunit;
import cn.stylefeng.guns.modular.system.dao.NoticeMapper;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertTrue;
/**
* 首页通知展示测试
*
* @author fengshuonan
* @date 2017-05-21 15:02
*/
public class BlackBoardTest extends BaseJunit {
@Autowired
NoticeMapper noticeMapper;
@Test
public void blackBoardTest() {
List<Map<String, Object>> notices = noticeMapper.list(null);
assertTrue(notices.size() > 0);
}
}
package cn.stylefeng.guns.system;
import cn.stylefeng.guns.base.BaseJunit;
import cn.stylefeng.guns.modular.system.dao.DeptMapper;
import cn.stylefeng.guns.modular.system.model.Dept;
import org.junit.Test;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* 字典服务测试
*
* @author fengshuonan
* @date 2017-04-27 17:05
*/
public class DeptTest extends BaseJunit {
@Resource
DeptMapper deptMapper;
@Test
public void addDeptTest() {
Dept dept = new Dept();
dept.setFullname("测试fullname");
dept.setNum(5);
dept.setPid(1);
dept.setSimplename("测试");
dept.setTips("测试tips");
dept.setVersion(1);
Integer insert = deptMapper.insert(dept);
assertEquals(insert, new Integer(1));
}
@Test
public void updateTest() {
Dept dept = this.deptMapper.selectById(24);
dept.setTips("哈哈");
boolean flag = dept.updateById();
assertTrue(flag);
}
@Test
public void deleteTest() {
Dept dept = this.deptMapper.selectById(24);
Integer integer = deptMapper.deleteById(dept);
assertTrue(integer > 0);
}
@Test
public void listTest() {
List<Map<String, Object>> list = this.deptMapper.list("总公司");
assertTrue(list.size() > 0);
}
}
package cn.stylefeng.guns.system;
import cn.stylefeng.guns.base.BaseJunit;
import cn.stylefeng.guns.modular.system.dao.DictMapper;
import cn.stylefeng.guns.modular.system.service.IDictService;
import org.junit.Assert;
import org.junit.Test;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* 字典服务测试
*
* @author fengshuonan
* @date 2017-04-27 17:05
*/
public class DictTest extends BaseJunit {
@Resource
IDictService dictService;
@Resource
DictMapper dictMapper;
@Test
public void addTest() {
String dictCode = "test";
String dictName = "字典测试";
String dictTips = "这是一个字典测试";
String dictValues = "1:测试1:1;2:测试2:2";
dictService.addDict(dictCode,dictName,dictTips, dictValues);
}
@Test
public void editTest() {
dictService.editDict(16, "tes","测试","备注", "1:测试1;2:测试2");
}
@Test
public void deleteTest() {
this.dictService.delteDict(16);
}
@Test
public void listTest() {
List<Map<String, Object>> list = this.dictMapper.list("性别");
Assert.assertTrue(list.size() > 0);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment