从零搭建项目开发框架-19系统登录及首页面

系统管理的各个功能开发完毕,下一步就该开发系统登录界面及首页面了,这样一个系统的雏形才能出来。

这里设计登录先以简单为主,像用不用验证码、密码输入错误次数等等都不做考虑,这是后续需要完成的事情,这里只校验账号密码是否成功,账户是否锁定,成功则设置session,并跳转至首页面。

1、登录页面图

登录页面图.png

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、系统首页

首页.png

登录成功后进入首页,这一块需要修改的是左侧菜单,需要根据用户的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方法即可

系统登录和进入首页还是比较复杂的,远远不是几句话就能讲清楚的,得需要深入的研究和琢磨才行

源码下载

本阶段详细源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,577评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 3,789评论 0 11
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,357评论 0 17
  • 二十岁你觉得迷茫吗?二十岁无论你是在上学,无论你是在工作,无论你是无业或是其他我没有想到的,但是我知道你们都会感...
    怀书呀阅读 206评论 0 0