05.綜合實例(iot-admin)

1.概述

本節將把「<strong>Java單體應用

」課程做一個階段性的總結,通過一個綜合的案例將所學知識完整實踐一下。

我們後續階段的課程還有:

  • Java微服務
  • 物聯網平臺構建
  • SaaS雲服務構建

為了後續課程的連續性,我們的 綜合實例 將搭建一個簡單的 <strong>IoT管理後臺 項目 <strong>iot-admin,實現用戶的登錄功能。

學習的過程要跟著練習並做好筆記!

2.創建項目

2.1.構建項目結構

創建項目文件夾

通過 IntelliJ IDEA 打開前述章節的項目結構,新增一個項目文件夾 <strong>iot-admin

創建 POM

添加一個 <strong>pom.xml

文件,文件內容如下:

<code><project>    <modelversion>4.0.0/<modelversion>    <groupid>net.work100.training.stage2/<groupid>    <artifactid>iot-admin/<artifactid>    <version>1.0.0-SNAPSHOT/<version>    <packaging>war/<packaging>    <dependencies>        <dependency>            <groupid>org.springframework/<groupid>            <artifactid>spring-context/<artifactid>            <version>5.2.3.RELEASE/<version>        /<dependency>        <dependency>            <groupid>javax.servlet/<groupid>            <artifactid>javax.servlet-api/<artifactid>            <version>4.0.1/<version>        /<dependency>              <dependency>            <groupid>junit/<groupid>            <artifactid>junit/<artifactid>            <version>4.12/<version>            <scope>test/<scope>        /<dependency>        <dependency>            <groupid>org.slf4j/<groupid>            <artifactid>slf4j-log4j12/<artifactid>            <version>1.7.25/<version>        /<dependency>    /<dependencies>/<project>/<code>

然後將 <strong>pom.xml 託管到 <strong>Maven。

完善Maven結構

完善下表的目錄結構:


Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

完善下表的目錄結構


項目結構如下圖:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

項目結構

完善 <strong>src/main/webapp/WEB-INF/web.xml 文件,內容如下:

<code><web-app>/<code>

完善項目架構

結合三層架構及MVC架構,在 <strong>src/main/java 下構建項目的類包結構,如下表:


Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

類包結構


項目結構如下圖:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

項目結構

配置 Spring 和 Log4j

在 <strong>src/main/resources 下添加 <strong>spring-context.xml 和 <strong>log4j.properties 文件:

<strong>spring-context.xml 代碼如下:

<code><beans>/<code>

<strong>log4j.properties 代碼如下:

<code>log4j.rootLogger=INFO, console, filelog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%nlog4j.appender.file=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.file.File=logs/log.loglog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.A3.MaxFileSize=1024KBlog4j.appender.A3.MaxBackupIndex=10log4j.appender.file.layout.ConversionPattern=%d %p [%c] - %m%n/<code>

構建前端框架結構

參照 <strong>Bootstrap - 環境搭建 - 實例 中的步驟構建 <strong>Bootstrap 的目錄結構:


Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

構建 Bootstrap 的目錄結構


在 <strong>src/main/webapp 下新建 <strong>index.jsp 文件,代碼如下:

<code>    <title>IoT-Admin/<title>    Hello IoT-Admin/<code>

項目結構如下圖:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

項目結構

配置 Tomcat

參考 <strong>架構模式 - 實踐練習 中所述的 <strong>Tomcat 配置方式將運行環境配好,並運行驗證效果:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

運行效果

3.使用AdminLTE模板

3.1.下載 AdminLTE

<strong>AdminLTE 是一個基於 <strong>Bootstrap 的後端模板引擎,最新版本基於 <strong>Bootstrap 4

構建,高度可定製且易於使用,適合從小型移動設備到大型臺式機的多種屏幕分辨率。 官網地址為 <strong>https://adminlte.io/ ,AdminLTE為開源軟件,可以前往 <strong>Github 獲取源碼。

本實例將使用 <strong>AdminLTE-3.0.2 版本進行演示,源碼包已經上傳至QQ群,請在 <strong>門戶首頁 下方加入QQ群獲取。

<strong>AdminLTE 下載後解壓縮,文件夾結構如下:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

AdminLTE 文件夾結構

將目錄下的文件 <strong>index.html 用瀏覽器打開運行,效果如下:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

AdminLTE Demo

請在使用 <strong>AdminLTE 框架前詳細瀏覽各頁面的展示效果,並參照 <strong>HTML 源碼瞭解 <strong>AdminLTE 的使用方法。

3.2.重構項目

因為 <strong>AdminLTE-3.0.2 是基於 <strong>Bootstrap 4 構建的,所以接下來我們重構我們的項目。

首先,刪除項目中的如下目錄:

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

然後,將 <strong>AdminLTE-3.0.2 下的文件夾複製到項目中,對應位置為:


Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

複製文件及文件夾


重構後的目錄結構為:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

重構後的目錄結構

4.創建登錄頁

我們參照 <strong>AdminLTE-3.0.2/pages/examples/login.html 源碼示例構建一個 <strong>iot-amdin 項目的登錄頁。

重構 <strong>index.jsp 頁面,代碼如下:

<code>            <title>IoT-Admin/<title>                <link>        <link>        <link>/<code>

運行 <strong>Tomcat ,啟動項目,效果如下:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

運行效果

5.登錄功能實現

後端代碼實現和 <strong>架構模式 - 實踐練習 章節所述方式類似,我們將其實現代碼進行改造。

5.1.創建 User 類

在包 <strong>net.work100.training.stage2.iot.admin 下新建一個包 <strong>entity,然後在其下新增一個 <strong>User 類

<strong>User.java 文件代碼如下:

<code>package net.work100.training.stage2.iot.admin.entity;import java.io.Serializable;/** * 

Title: User

*

Description:

* * @author liuxiaojun * @date 2020-02-13 13:21 * ------------------- History ------------------- * <date> <author> <desc> * 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 + '\\'' + '}'; }}/<desc>/<author>/<date>/<code>

5.2.創建 UserDao 接口及其實現 UserDaoImpl

在包 <strong>net.work100.training.stage2.iot.admin.dao 下新建一個接口 <strong>UserDao

<strong>UserDao.java 文件代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 2020-02-13 liuxiaojun 初始創建 * ----------------------------------------------- */public interface UserDao { /** * 根據ID及密碼獲取用戶信息 * * @param loginId 登錄ID * @param loginPwd 登錄密碼 * @return */ User getUser(String loginId, String loginPwd);}/<desc>/<author>/<date>/<code>

在包 <strong>net.work100.training.stage2.iot.admin.dao 下新增一個類包 <strong>impl,然後在 <strong>impl 包下新建一個類 <strong>UserDaoImpl

<strong>UserDaoImpl.java 文件代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 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; }}/<desc>/<author>/<date>/<code>

5.3.創建 UserService 接口及其實現 UserServiceImpl

在包 <strong>net.work100.training.stage2.iot.admin.service 下新建一個接口 <strong>UserService

<strong>UserService.java 文件代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 2020-02-13 liuxiaojun 初始創建 * ----------------------------------------------- */public interface UserService { /** * 登錄驗證 * * @param loginId 登錄ID * @param loginPwd 登錄密碼 * @return */ User login(String loginId, String loginPwd);}/<desc>/<author>/<date>/<code>

在包 <strong>net.work100.training.stage2.iot.admin.service 下新增一個類包 <strong>impl,然後在 <strong>impl

包下新建一個類 <strong>UserServiceImpl

<strong>UserServiceImpl.java 文件代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 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); }}/<desc>/<author>/<date>/<code>

5.4.創建 LoginController

實現 Servlet

在包 <strong>net.work100.training.stage2.iot.admin.web 下新增一個類包 <strong>controller,然後在 <strong>controller 包下新建一個類 <strong>LoginController

<strong>LoginController.java 文件代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 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); } }}/<desc>/<author>/<date>/<code>

配置 Servlet 映射

修改 <strong>src/main/webapp/WEB-INF/web.xml 文件,內容如下:

<code><web-app>    <servlet>        <servlet-name>loginController/<servlet-name>        <servlet-class>net.work100.training.stage2.iot.admin.web.controller.LoginController/<servlet-class>    /<servlet>    <servlet-mapping>        <servlet-name>loginController/<servlet-name>        <url-pattern>/login/<url-pattern>    /<servlet-mapping>/<web-app>/<code> 

新建登錄成功後展示頁面 main.jsp

為了模擬登錄驗證後的效果,我們在文件夾 <strong>src/main/webapp/ 下新建文件 <strong>main.jsp,登錄成功後將跳轉至此頁面,代碼如下:

<code>    <title>首頁/<title>這裡是首頁/<code>

5.5.運行

啟動 <strong>Tomcat 進行登錄驗證,表單輸入以下正確的登錄數據:


Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

正確的登錄數據


頁面將跳轉至 <strong>main.jsp,如下圖:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

登錄成功後跳轉頁

輸入錯誤登錄數據時,重新返回到登錄頁。

5.6.使用 Spring IoC

新建 SpringContext 類

新建一個類包 <strong>net.work100.training.stage2.iot.admin.commons.context,然後在其下創建 <strong>SpringContext 類

<strong>SpringContext.java 文件代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 2020-02-13 liuxiaojun 初始創建 * ----------------------------------------------- */public final class SpringContext { public Object getBean(String beanId) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml"); return context.getBean(beanId); }}/<desc>/<author>/<date>/<code>

配置 spring-context.xml

修改 <strong>src/main/resources/spring-context.xml 文件,內容如下:

<code><beans>        <bean>        <bean>/<beans>/<code>

修改 UserServiceImpl

修改 <strong>UserServiceImpl.java 代碼,如下:

<code>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 ------------------- * <date> <author> <desc> * 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); }}/<desc>/<author>/<date>/<code>

修改 LoginController

修改 <strong>LoginController.java

代碼,如下:

<code>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 ------------------- * <date> <author> <desc> * 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); } }}/<desc>/<author>/<date>/<code>

重新運行

重啟 <strong>Tomcat 驗證運行效果。

6.提升用戶體驗

當用戶輸入錯誤的ID或密碼時驗證會失敗,然後頁面會跳轉回登錄頁。

從用戶體驗角度考慮,需要給用戶一個 <strong>提示信息,告知其登錄驗證失敗了,下面我們來實現這個功能。

6.1.改造 LoginController

登錄驗證失敗後增加返回錯誤信息 <strong>req.setAttribute("message", "登錄ID或登錄密碼錯誤"); ,完整代碼如下:

<code>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 ------------------- * <date> <author> <desc> * 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); } }}/<desc>/<author>/<date>/<code>

6.2.改造 index.jsp

引入 JSTL 依賴

這裡我們會用到 <strong>JSTL 表達式,所以需要先在 <strong>pom.xml 文件中引入依賴:

<code><dependency>    <groupid>javax.servlet/<groupid>    <artifactid>jstl/<artifactid>    <version>1.2/<version>/<dependency>/<code>

增加 taglib 指令

在 <strong>index.jsp 文件頭增加如下代碼:

<code>

增加錯誤提示

在 <strong>index.jsp 文件的 <strong>form 表單上方增加如下代碼:

<code>    
<button>×/<button> ${message}
/<code>

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

<code>            <title>IoT-Admin/<title>                <link>     
<link> <link>/<code>

6.3.驗證效果

運行 <strong>Tomcat ,輸入錯誤的登錄數據,頁面效果如下:

Java單體應用 - 常用框架 - 05.綜合實例(iot-admin)

錯誤提示效果

7.實例源碼

實例源碼已經託管到如下地址:

  • https://github.com/work100-net/training-stage2/tree/master/iot-admin
  • https://gitee.com/work100-net/training-stage2/tree/master/iot-admin


分享到:


相關文章: