系统管理的各个功能开发完毕,下一步就该开发系统登录界面及首页面了,这样一个系统的雏形才能出来。
这里设计登录先以简单为主,像用不用验证码、密码输入错误次数等等都不做考虑,这是后续需要完成的事情,这里只校验账号密码是否成功,账户是否锁定,成功则设置session,并跳转至首页面。
1、登录页面图
jCookie.js
引入这个js的目的是,用cookie来保存是否选择记住我
这个checkbox。
userBrower.js
引入这个的目的是获取浏览器的类型及版本号,提交给后台记录下来
UserSession.java
public class UserSession implements Serializable {
private static final long serialVersionUID = 1629527703944211785L;
private int userId;//用户id
private String userIp;//用户IP
private String username;//用户名 即登录账号
private String realname;//真实姓名
private int roleId;//角色id
private String roleName;//角色名称
@Override
public String toString() {
return "UserSession{" +
"userId=" + userId +
", userIp='" + userIp + '\'' +
", username='" + username + '\'' +
", realname='" + realname + '\'' +
", roleId=" + roleId +
", roleName='" + roleName + '\'' +
'}';
}
// set get方法省略
}
用户UserSession是一个对象,里面包括ip、userId、用户名、姓名、角色id、角色等常用信息。
SessionUtil.java
public class SessionUtil {
/**
* 功能描述:获取用户session
*
* @param request
* @return UserSession
* @version 1.0.0
*/
public static UserSession getUserSession(HttpServletRequest request) {
if (request.getSession().getAttribute("userSession") != null)
return (UserSession) request.getSession().getAttribute("userSession");
else {
// UserSession userSession = new UserSession();
// userSession.setRoleId(1);
// userSession.setUserId(1);
// userSession.setUsername("admin");
// userSession.setRealname("admin");
// return userSession;
return null;
}
}
/**
* 获取当前操作人
*
* @param request
* @return
*/
public static String getRealname(HttpServletRequest request) {
return getUserSession(request).getRealname();
}
}
这个工具类的目的是统一获取UserSession
checkLogin()校验登录方法
@RequestMapping("/checkLogin")
public void checkLogin(HttpServletRequest request, HttpServletResponse response, String username, String password) {
// // 校验账号和密码是否都为空
if (StringUtil.isNullOrEmpty(username) || StringUtil.isNullOrEmpty(password)) {
WebUtil.out(response, JsonUtil.createOperaStr(false, "用户名或密码错误"));
return;
}
SysUser sysUser = sysUserService.getByUsername(username);
if (sysUser == null || !sysUserService.checkPass(sysUser, password)) {
String json = "{\"success\":" + false + ",\"msgText\":\"用户名或密码错误\"}";
WebUtil.out(response, json);
} else {
if (sysUser.getStatus() == 2) {
WebUtil.out(response, JsonUtil.createOperaStr(false, "该用户已锁定"));
} else {
String ip = StringUtil.getIp(request);
UserSession userSession = new UserSession();
userSession.setUserId(sysUser.getId());//userId
userSession.setUsername(sysUser.getUsername());//username
userSession.setUserIp(ip);//IP地址
userSession.setRoleId(sysUser.getRoleId());
userSession.setRoleName(sysUser.getRoleName());// 角色
userSession.setRealname(sysUser.getRealname());
request.getSession().setAttribute("userSession", userSession);
request.getSession().setMaxInactiveInterval(1000 * 60 * 30);// 设置过期时间30分钟
// 插入登录日志
SysUserLogin sysUserLogin = new SysUserLogin();
sysUserLogin.setUserId(sysUser.getId());
sysUserLogin.setLoginDate(new Date());
sysUserLogin.setLoginIp(ip);
sysUserLogin.setTerminal(WebUtil.getSafeStr(request.getParameter("terminal")));
sysUserLogin.setExplorerType(WebUtil.getSafeStr(request.getParameter("explorerType")));
sysUserLogin.setExplorerVersion(WebUtil.getSafeStr(request.getParameter("explorerVersion")));
userLoginService.add(sysUserLogin);
WebUtil.out(response, JsonUtil.createOperaStr(true, "登录成功"));
}
}
}
这一段的代码不复杂,就是根据获取的用户名和密码与数据库取到的进行比较,如果一样且当前用户未锁定,则登录成功,记录session,并记录登录日志。
2、系统首页
登录成功后进入首页,这一块需要修改的是左侧菜单,需要根据用户的roleId动态从数据库中读取。这里采用自定义标签函数的方式,在service层写好生成的菜单代码。
webtag.tld增加配置
<function>
<description>生成菜单</description>
<name>createMenu</name>
<function-class>com.critc.plat.util.web.WebTag</function-class>
<function-signature>java.lang.String createMenu(javax.servlet.http.HttpServletRequest)</function-signature>
</function>
WebTag.java增加代码
/**
* 生成菜单
*
* @param request 请求
* @return 菜单
*/
public static String createMenu(HttpServletRequest request) {
UserSession userSession = SessionUtil.getUserSession(request);
SysRoleService sysRoleService = SpringContextHolder.getBean("sysRoleService");
return sysRoleService.createMenuStr(userSession.getRoleId());
}
SysRoleService.java增加createMenuStr代码
/**
* 根据角色id生成该角色对应的菜单
*
* @param role_id
* @return
*/
public String createMenuStr(int role_id) {
String menu = EhCacheUtil.get("sysCache", "roleMenu_" + role_id);
if (menu == null) {
StringBuffer sb = new StringBuffer();
List<SysResource> listResource = sysResourceDao.list();// 模块列表
List<SysRoleResource> listRoleResource = sysRoleresourceDao.listRoleResourceByType(role_id, 1);// 角色模块列表
List<Integer> displayResourceIdList = new ArrayList<>();
for (SysRoleResource sysRoleResource : listRoleResource) {
displayResourceIdList.add(sysRoleResource.getResourceId());
}
for (SysResource sysResource : listResource) {
if (sysResource.getParentId() == 1 && displayResourceIdList.contains(sysResource.getId())) {
sb.append("<li class=\"\"><a href=\"#\" class=\"dropdown-toggle\"> <i class=\"menu-icon fa "
+ sysResource.getIconImg() + "\"></i> <span class=\"menu-text\"> " + sysResource.getName()
+ " </span> <b class=\"arrow fa fa-angle-down\"></b></a> <b class=\"arrow\"></b><ul class=\"submenu\">");
for (SysResource sysResourceChild : listResource) {
if (sysResourceChild.getParentId() == sysResource.getId()
&& displayResourceIdList.contains(sysResourceChild.getId())) {
sb.append("<li id=\"module_" + sysResourceChild.getId() + "\" class=\"\"><a href=\""
+ pubConfig.getDynamicServer() + "/" + sysResourceChild.getUrl()
+ "\" target=\"" + sysResourceChild.getTarget() + "\"> <i class=\"menu-icon fa fa-caret-right\"></i>" + sysResourceChild.getName()
+ "</a> <b class=\"arrow\"></b></li>");
}
}
sb.append("</ul></li>");
}
}
menu = sb.toString();
EhCacheUtil.put("sysCache", "roleMenu_" + role_id, menu);
}
return menu;
}
这段代码的原理是先根据roleId从EhCache的缓存读取菜单的字符串,如果没有则生成该字符串。生成的原理很简单,可以参照ACE菜单的代码,就是<ul><li>的迭代。生成完放入EhCache中。
EhCacheUtil.java 缓存工具类
增加依赖
<!-- EHCache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
</dependency>
public class EhCacheUtil {
private static volatile EhCacheUtil ehCacheUtil;
private static volatile CacheManager cacheManager;
private static Logger log = LoggerFactory.getLogger(EhCacheUtil.class);
private static String confPath = "/ehcache.xml";//定义配置文件路径
public static EhCacheUtil getInstance() {
if (null == ehCacheUtil) {
synchronized (EhCacheUtil.class) {
if (null == ehCacheUtil) {
ehCacheUtil = new EhCacheUtil();
}
}
}
return ehCacheUtil;
}
static {
try {
URL url = EhCacheUtil.class.getResource(confPath);
cacheManager = CacheManager.create(url);
log.info("ehcache初始化");
} catch (Exception e) {
e.printStackTrace();
log.info("ehcache初始化失败");
}
}
public static CacheManager getCacheManager() {
return cacheManager;
}
static Cache getOrAddCache(String cacheName) {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
synchronized (cacheManager) {
cache = cacheManager.getCache(cacheName);
if (cache == null) {
log.warn("Could not find cache config [" + cacheName + "], using default.");
cacheManager.addCacheIfAbsent(cacheName);
cache = cacheManager.getCache(cacheName);
log.info("Cache [" + cacheName + "] started.");
}
}
}
return cache;
}
public static void put(String cacheName, Object key, Object value) {
getOrAddCache(cacheName).put(new Element(key, value));
}
@SuppressWarnings("unchecked")
public static <T> T get(String cacheName, Object key) {
Element element = getOrAddCache(cacheName).get(key);
return element != null ? (T) element.getObjectValue() : null;
}
@SuppressWarnings("rawtypes")
public static List getKeys(String cacheName) {
return getOrAddCache(cacheName).getKeys();
}
public static void remove(String cacheName, Object key) {
getOrAddCache(cacheName).remove(key);
}
public static void removeAll(String cacheName) {
getOrAddCache(cacheName).removeAll();
}
public static void main(String[] args) {
EhCacheUtil.put("sysCache", "cache", "Hello EhCache");
String value = EhCacheUtil.get("sysCache", "cache");
System.out.println(value);
}
}
上面是EhCache的工具类用法,很简单,核心就三个方法,put、get、removeAll三个方法。
具体EHCache的用法,参见
2.1EhCache
SpringContextHolder
由于在WebTag.java
这个静态方法中,是无法直接注入SysRoleService
这个类的,所以必须从Spring的容器中根据方法名直接获取。
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
*/
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext; //NOSONAR
}
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/**
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
* 如果有多个Bean符合Class, 取出第一个.
*/
public static <T> T getBean(Class<T> requiredType) {
checkApplicationContext();
return applicationContext.getBean(requiredType);
}
/**
* 清除applicationContext静态变量.
*/
public static void cleanApplicationContext() {
applicationContext = null;
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
}
}
}
代码比较简单,不过需要在Spring配置中applicationContext.xml
增加以下一句话:
<bean class="com.critc.plat.core.spring.SpringContextHolder"
lazy-init="false"/>
menu.jspf
<ul class="nav nav-list">
<li class="active" id="menu-statistic"><a href="${dynamicServer}/index.htm" id="module_statistic"> <i
class="menu-icon fa fa-tachometer"></i> <span class="menu-text"> 功能菜单 </span>
</a> <b class="arrow"></b></li>
${critc:createMenu(pageContext.request) }
</ul>
调用标签的createMenu
方法即可