原文地址:http://www.work100.net/training/monolithic-frameworks-example.html
更多教程:光束云 - 免费课程

综合实例

序号 文内章节 视频
1 概述 -
2 创建项目 -
3 使用AdminLTE模板 -
4 创建登录页 -
5 登录功能实现 -
6 提升用户体验 -
7 实例源码 -

请参照如上章节导航进行阅读

1.概述

本节将把「Java单体应用」课程做一个阶段性的总结,通过一个综合的案例将所学知识完整实践一下。

我们后续阶段的课程还有:

  • Java微服务
  • 物联网平台构建
  • SaaS云服务构建

为了后续课程的连续性,我们的 综合实例 将搭建一个简单的 IoT管理后台 项目 iot-admin,实现用户的登录功能。

学习的过程要跟着练习并做好笔记!

2.创建项目

2.1.构建项目结构

创建项目文件夹

通过 IntelliJ IDEA 打开前述章节的项目结构,新增一个项目文件夹 iot-admin

创建 POM

添加一个 pom.xml 文件,文件内容如下:



    4.0.0

    net.work100.training.stage2
    iot-admin
    1.0.0-SNAPSHOT
    war

    
        
            org.springframework
            spring-context
            5.2.3.RELEASE
        
        
            javax.servlet
            javax.servlet-api
            4.0.1
              
        
            junit
            junit
            4.12
            test
        
        
            org.slf4j
            slf4j-log4j12
            1.7.25
        
    

然后将 pom.xml 托管到 Maven

完善Maven结构

完善下表的目录结构:

目录或文件 说明
pom.xml POM文件
src/main/java 源码文件夹
src/main/resources 资源文件夹
src/main/webapp 网站文件夹
src/main/webapp/WEB-INF 网站配置文件夹
src/main/webapp/WEB-INF/web.xml 网站配置文件
src/test/java 测试源码文件夹

项目结构如下图:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第1张图片

完善 src/main/webapp/WEB-INF/web.xml 文件,内容如下:




完善项目架构

结合三层架构及MVC架构,在 src/main/java 下构建项目的类包结构,如下表:

类包 说明
net.work100.training.stage2.iot.admin 项目总的类包
net.work100.training.stage2.iot.admin.dao 数据访问层
net.work100.training.stage2.iot.admin.service 服务层
net.work100.training.stage2.iot.admin.web Web层

项目结构如下图:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第2张图片

配置 Spring 和 Log4j

src/main/resources 下添加 spring-context.xmllog4j.properties 文件:

spring-context.xml 代码如下:




log4j.properties 代码如下:

log4j.rootLogger=INFO, console, file

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n

log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=logs/log.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.MaxFileSize=1024KB
log4j.appender.A3.MaxBackupIndex=10
log4j.appender.file.layout.ConversionPattern=%d %p [%c] - %m%n

构建前端框架结构

参照 Bootstrap - 环境搭建 - 实例 中的步骤构建 Bootstrap 的目录结构:

目录 说明
src/main/webapp/assets/ 静态资源文件目录
src/main/webapp/assets/css/ 自定义样式
src/main/webapp/assets/images/ 自定义图片
src/main/webapp/assets/js/ 自定义JS
src/main/webapp/assets/plugins/ 插件
src/main/webapp/assets/plugins/bootstrap/ Bootstrap插件
src/main/webapp/assets/plugins/bootstrap/css/ Bootstrap 样式表文件
src/main/webapp/assets/plugins/bootstrap/font-awesome/ 第三方字体
src/main/webapp/assets/plugins/bootstrap/js/ Bootstrap JS文件
src/main/webapp/assets/plugins/bootstrap/jquery-3.4.1.min.js jQuery

src/main/webapp 下新建 index.jsp 文件,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    IoT-Admin


    Hello IoT-Admin

项目结构如下图:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第3张图片

配置 Tomcat

参考 架构模式 - 实践练习 中所述的 Tomcat 配置方式将运行环境配好,并运行验证效果:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第4张图片

3.使用AdminLTE模板

3.1.下载 AdminLTE

AdminLTE 是一个基于 Bootstrap 的后端模板引擎,最新版本基于 Bootstrap 4 构建,高度可定制且易于使用,适合从小型移动设备到大型台式机的多种屏幕分辨率。
官网地址为 ; ,AdminLTE为开源软件,可以前往 ; 获取源码。

本实例将使用 AdminLTE-3.0.2 版本进行演示,源码包已经上传至QQ群,请在 门户首页 下方加入QQ群获取。

AdminLTE 下载后解压缩,文件夹结构如下:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第5张图片

将目录下的文件 index.html 用浏览器打开运行,效果如下:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第6张图片

请在使用 AdminLTE 框架前详细浏览各页面的展示效果,并参照 HTML 源码了解 AdminLTE 的使用方法。

3.2.重构项目

因为 AdminLTE-3.0.2 是基于 Bootstrap 4 构建的,所以接下来我们重构我们的项目。

首先,删除项目中的如下目录:

  • src/main/webapp/assets/plugins
  • src/main/webapp/assets/css
  • src/main/webapp/assets/images
  • src/main/webapp/assets/js

然后,将 AdminLTE-3.0.2 下的文件夹复制到项目中,对应位置为:

AdminLTE-3.0.2 目录 项目中目录
AdminLTE-3.0.2/plugins src/main/webapp/assets/plugins
AdminLTE-3.0.2/dist/css src/main/webapp/assets/css
AdminLTE-3.0.2/dist/images src/main/webapp/assets/images
AdminLTE-3.0.2/dist/js src/main/webapp/assets/js

重构后的目录结构为:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第7张图片

4.创建登录页

我们参照 AdminLTE-3.0.2/pages/examples/login.html 源码示例构建一个 iot-amdin 项目的登录页。

重构 index.jsp 页面,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>



    
    
    IoT-Admin
    
    

    
    
    
    
    
    













运行 Tomcat ,启动项目,效果如下:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第8张图片

5.登录功能实现

后端代码实现和 架构模式 - 实践练习 章节所述方式类似,我们将其实现代码进行改造。

5.1.创建 User 类

在包 net.work100.training.stage2.iot.admin 下新建一个包 entity,然后在其下新增一个 User

User.java 文件代码如下:

package net.work100.training.stage2.iot.admin.entity;

import java.io.Serializable;

/**
 * 

Title: User

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:21 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class User implements Serializable { private String userName; private String loginId; private String loginPwd; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getLoginId() { return loginId; } public void setLoginId(String loginId) { this.loginId = loginId; } public String getLoginPwd() { return loginPwd; } public void setLoginPwd(String loginPwd) { this.loginPwd = loginPwd; } @Override public String toString() { return "User{" + "userName='" + userName + '\'' + ", loginId='" + loginId + '\'' + '}'; } }

5.2.创建 UserDao 接口及其实现 UserDaoImpl

在包 net.work100.training.stage2.iot.admin.dao 下新建一个接口 UserDao

UserDao.java 文件代码如下:

package net.work100.training.stage2.iot.admin.dao;

import net.work100.training.stage2.iot.admin.entity.User;

/**
 * 

Title: UserDao

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:16 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public interface UserDao { /** * 根据ID及密码获取用户信息 * * @param loginId 登录ID * @param loginPwd 登录密码 * @return */ User getUser(String loginId, String loginPwd); }

在包 net.work100.training.stage2.iot.admin.dao 下新增一个类包 impl,然后在 impl 包下新建一个类 UserDaoImpl

UserDaoImpl.java 文件代码如下:

package net.work100.training.stage2.iot.admin.dao.impl;

import net.work100.training.stage2.iot.admin.dao.UserDao;
import net.work100.training.stage2.iot.admin.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

Title: UserDaoImpl

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:23 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class UserDaoImpl implements UserDao { private static final Logger logger = LoggerFactory.getLogger(UserDaoImpl.class); public User getUser(String loginId, String loginPwd) { logger.debug("调用方法 getUser(loginId:{}, loginPwd:{})", loginId, loginPwd); // 根据 loginId 查询出用户信息 User user = getUserByLoginId(loginId); if (user != null) { // 验证 loginPwd 是否正确(区分大小写) if (user.getLoginPwd().equals(loginPwd)) { return user; } } return null; } /** * 获取模拟的用户数据 * * @param loginId 登录ID * @return */ private User getUserByLoginId(String loginId) { // 模拟 DB 存在的用户数据 User dbUser = new User(); dbUser.setUserName("Xiaojun"); dbUser.setLoginId("admin"); dbUser.setLoginPwd("admin"); // 判断是否存在 loginId 的用户(忽略大小写) if (dbUser.getLoginId().equalsIgnoreCase(loginId)) { logger.info("匹配上用户:{}", dbUser); return dbUser; } logger.warn("未匹配任何用户,将返回 null"); return null; } }

5.3.创建 UserService 接口及其实现 UserServiceImpl

在包 net.work100.training.stage2.iot.admin.service 下新建一个接口 UserService

UserService.java 文件代码如下:

package net.work100.training.stage2.iot.admin.service;

import net.work100.training.stage2.iot.admin.entity.User;

/**
 * 

Title: UserService

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:25 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public interface UserService { /** * 登录验证 * * @param loginId 登录ID * @param loginPwd 登录密码 * @return */ User login(String loginId, String loginPwd); }

在包 net.work100.training.stage2.iot.admin.service 下新增一个类包 impl,然后在 impl 包下新建一个类 UserServiceImpl

UserServiceImpl.java 文件代码如下:

package net.work100.training.stage2.iot.admin.service.impl;

import net.work100.training.stage2.iot.admin.dao.UserDao;
import net.work100.training.stage2.iot.admin.dao.impl.UserDaoImpl;
import net.work100.training.stage2.iot.admin.entity.User;
import net.work100.training.stage2.iot.admin.service.UserService;

/**
 * 

Title: UserServiceImpl

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:26 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); public User login(String loginId, String loginPwd) { return userDao.getUser(loginId, loginPwd); } }

5.4.创建 LoginController

实现 Servlet

在包 net.work100.training.stage2.iot.admin.web 下新增一个类包 controller,然后在 controller 包下新建一个类 LoginController

LoginController.java 文件代码如下:

package net.work100.training.stage2.iot.admin.web.controller;

import net.work100.training.stage2.iot.admin.entity.User;
import net.work100.training.stage2.iot.admin.service.UserService;
import net.work100.training.stage2.iot.admin.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 

Title: LoginController

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:28 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class LoginController extends HttpServlet { private UserService userService = new UserServiceImpl(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { User user = userService.login("admin", "admin"); System.out.println("--------------doGet test(begin)-----------------"); System.out.println(user); System.out.println("--------------doGet test(end)-----------------"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String loginId = req.getParameter("loginId"); String loginPwd = req.getParameter("loginPwd"); User user = userService.login(loginId, loginPwd); // 登录成功 if (user != null) { // 重定向到首页 resp.sendRedirect("/main.jsp"); } // 登录失败 else { // 跳转回登录页 req.getRequestDispatcher("/index.jsp").forward(req, resp); } } }

配置 Servlet 映射

修改 src/main/webapp/WEB-INF/web.xml 文件,内容如下:




    
        loginController
        net.work100.training.stage2.iot.admin.web.controller.LoginController
    
    
        loginController
        /login
    

新建登录成功后展示页面 main.jsp

为了模拟登录验证后的效果,我们在文件夹 src/main/webapp/ 下新建文件 main.jsp,登录成功后将跳转至此页面,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    首页


这里是首页

5.5.运行

启动 Tomcat 进行登录验证,表单输入以下正确的登录数据:

名称
用户名 admin
密码 admin

页面将跳转至 main.jsp,如下图:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第9张图片

输入错误登录数据时,重新返回到登录页。

5.6.使用 Spring IoC

新建 SpringContext 类

新建一个类包 net.work100.training.stage2.iot.admin.commons.context,然后在其下创建 SpringContext

SpringContext.java 文件代码如下:

package net.work100.training.stage2.iot.admin.commons.context;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 

Title: SpringContext

*

Description:

* * @author liuxiaojun * @date 2020-02-13 14:31 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public final class SpringContext { public Object getBean(String beanId) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml"); return context.getBean(beanId); } }

配置 spring-context.xml

修改 src/main/resources/spring-context.xml 文件,内容如下:




    
    

    
    

修改 UserServiceImpl

修改 UserServiceImpl.java 代码,如下:

package net.work100.training.stage2.iot.admin.service.impl;

import net.work100.training.stage2.iot.admin.commons.context.SpringContext;
import net.work100.training.stage2.iot.admin.dao.UserDao;
import net.work100.training.stage2.iot.admin.entity.User;
import net.work100.training.stage2.iot.admin.service.UserService;

/**
 * 

Title: UserServiceImpl

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:26 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class UserServiceImpl implements UserService { private SpringContext context = new SpringContext(); public User login(String loginId, String loginPwd) { UserDao userDao = (UserDao) context.getBean("userDao"); return userDao.getUser(loginId, loginPwd); } }

修改 LoginController

修改 LoginController.java 代码,如下:

package net.work100.training.stage2.iot.admin.web.controller;

import net.work100.training.stage2.iot.admin.commons.context.SpringContext;
import net.work100.training.stage2.iot.admin.entity.User;
import net.work100.training.stage2.iot.admin.service.UserService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 

Title: LoginController

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:28 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class LoginController extends HttpServlet { private SpringContext context = new SpringContext(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { UserService userService = (UserService) context.getBean("userService"); User user = userService.login("admin", "admin"); System.out.println("--------------doGet test(begin)-----------------"); System.out.println(user); System.out.println("--------------doGet test(end)-----------------"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { UserService userService = (UserService) context.getBean("userService"); String loginId = req.getParameter("loginId"); String loginPwd = req.getParameter("loginPwd"); User user = userService.login(loginId, loginPwd); // 登录成功 if (user != null) { // 重定向到首页 resp.sendRedirect("/main.jsp"); } // 登录失败 else { // 跳转回登录页 req.getRequestDispatcher("/index.jsp").forward(req, resp); } } }

重新运行

重启 Tomcat 验证运行效果。

6.提升用户体验

当用户输入错误的ID或密码时验证会失败,然后页面会跳转回登录页。

从用户体验角度考虑,需要给用户一个 提示信息,告知其登录验证失败了,下面我们来实现这个功能。

6.1.改造 LoginController

登录验证失败后增加返回错误信息 req.setAttribute("message", "登录ID或登录密码错误"); ,完整代码如下:

package net.work100.training.stage2.iot.admin.web.controller;

import net.work100.training.stage2.iot.admin.commons.context.SpringContext;
import net.work100.training.stage2.iot.admin.entity.User;
import net.work100.training.stage2.iot.admin.service.UserService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 

Title: LoginController

*

Description:

*

Url: http://www.work100.net/training/monolithic-frameworks-example.html

* * @author liuxiaojun * @date 2020-02-13 13:28 * ------------------- History ------------------- * * 2020-02-13 liuxiaojun 初始创建 * ----------------------------------------------- */ public class LoginController extends HttpServlet { private SpringContext context = new SpringContext(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { UserService userService = (UserService) context.getBean("userService"); User user = userService.login("admin", "admin"); System.out.println("--------------doGet test(begin)-----------------"); System.out.println(user); System.out.println("--------------doGet test(end)-----------------"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { UserService userService = (UserService) context.getBean("userService"); String loginId = req.getParameter("loginId"); String loginPwd = req.getParameter("loginPwd"); User user = userService.login(loginId, loginPwd); // 登录成功 if (user != null) { // 重定向到首页 resp.sendRedirect("/main.jsp"); } // 登录失败 else { // 跳转回登录页 req.setAttribute("message", "登录ID或登录密码错误"); req.getRequestDispatcher("/index.jsp").forward(req, resp); } } }

6.2.改造 index.jsp

引入 JSTL 依赖

这里我们会用到 JSTL 表达式,所以需要先在 pom.xml 文件中引入依赖:


    javax.servlet
    jstl
    1.2

增加 taglib 指令

index.jsp 文件头增加如下代码:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

增加错误提示

index.jsp 文件的 form 表单上方增加如下代码:


    
${message}

完整 index.jsp 文件代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>



    
    
    IoT-Admin
    
    

    
    
    
    
    
    













6.3.验证效果

运行 Tomcat ,输入错误的登录数据,页面效果如下:

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第10张图片

7.实例源码

实例源码已经托管到如下地址:

  • ;
  • ;

上一篇:Log4j

下一篇:Spring Web


如果对课程内容感兴趣,可以扫码关注我们的 公众号QQ群,及时关注我们的课程更新

Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第11张图片
Java单体应用 - 常用框架 - 05.综合实例(iot-admin)_第12张图片