[手把手教程][JavaWeb]優雅的SSM應用(三)
文章正式改名為:[手把手教程][JavaWeb]優雅的SSM應用
這幾天一直在踩坑,為什么這么說呢,主要是一直自己沒找到優雅的方式來實現一些東西。
雖然說前面也做了一些功能模塊,但是總感覺不對勁,畢竟也是剛轉做后端。
為了方便手機端用戶,盡量使用簡單的markdown語法和簡單的頁面結構。
后面朋友給了我一些他們公司同事寫的demo,雖然說不上是牛逼的作品,但是確實符合我現在的需要。畢竟人家的實現方式也是經過實戰項目演練出來的。
- 再次安利一波,博客地址:acheng1314.cn
工具
- IDE為idea15
- JDK環境為1.8
- maven版本為maven3
- Mysql版本為5.5.27
- Tomcat版本為7.0.52
- 流程圖繪制(xmind)
本期目標
- 倉庫管理系統的登錄注冊模塊實現
- 其他一些開發細節的體現
- 功能模塊分層設計的具體實現
其他
- 我這姑且算是文章吧,文章都是先用有道云筆記寫的,然后在簡書上面查看有沒有沖突,最后再放到稀土掘金上面
- 但是稀土掘金上面文章出問題了,反饋上去也沒能解決,本來想抓包看看他們的數據的,后面還是沒做
- ···其他想說的就太多了,但都是不是今天的主題。
注冊
首先,我們webapp要實現用戶登錄,必須得能新建用戶。所以,我們先把注冊用戶放在前面。
- 預期功能:
- 打開注冊頁面
- 填寫注冊信息
- 點擊注冊
- 顯示注冊后的提示信息
有了功能后,我們就能大概明白我們是想要一個什么樣子的注冊模塊了。
- 一個web注冊頁面
- web頁面能進行基本的數據效驗
- 服務器能存儲用戶的注冊信息
- 注冊動作完成后,返回提示頁面。
一般的,我們在開發中,有了大概樣子的功能模塊,我們需要整理一下業務流程和程序執行流程(在企業開發中,有項目經理的話,一般這些都是他們整理出來的,我們只需要開發實現就行。)經過一番撓頭,大概的流程圖如下所示:

上圖說明:
- 我們在web頁面完成注冊信息的填寫后,我們需要在web頁面做一些基本的數據效驗。當然后面我們會演示。
- 注冊信息通過基本的驗證后,我們直接提交到服務器,tomact → servelt → spring 。我們的后端程序,一切都被spring接管了,所以,我們需要在spring中完成這些功能。
- spring和外界通信,我們都是在Controller中完成。所以我們在Controller中處理數據。
- 當數據通過了Controller中的校驗后,我們需要在Controller中來查找數據庫是否存在同樣的用戶名,通用的數據操作流程如:Controller → Service → Dao。
- 前面我們提到過,Service是為我們的程序提供服務的,我們盡量每個Service對應一個Dao,這樣我們只需要提供單一的數據驅動,在外層進行業務組裝,這樣就能達到我們的目的,同樣的,我們這樣也能將程序解耦,以后的維護也就相對簡單了。
好的,我們上面已經把思路想明白了?,F在我們接著就開始實戰。
- 生成注冊頁面的連接。
我們要生成一個連接,經過查找資料,我們知道我們需要創建一個Controller的類。代碼如下:
@Controller
@RequestMapping("/mvc")
public class MainController {
/**
* 登陸頁面
* @return
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(){
return "login";
}
}
在上面我們使用了@Controller和@RequestMapping("/mvc")注解。詳細資料點這里。
通俗的來說,我們需要在我們前面配置的Controller路徑中,建立使用@Controller的注解的類告訴Spring這是一個控制器。
在類上面的 @RequestMapping("/mvc") ,是說明這個類的訪問地址是 /mvc 。
在方法上面的 @RequestMapping(value = "/login",method = RequestMethod.GET) ,是說明我這個方法的訪問地址是 /mvc/login ,請求方式是http請求的get方式。
這里我的方法是String方法,則是直接返回一個web頁面的名字。
當然,我們并不需要說直接去設定某個jsp文件。我們需要的是在這里指定好名稱,然后使用對應的自動完成就能創建出那個jsp文件。
然后我們直接在jsp文件中填寫對應的代碼就行了。
好的,基本的東西我們都說了,那么我們先去百度找一個登錄界面(一定要能看,不能那啥太直接的粗糙的東西,畢竟我們都是有品位的人)。如下圖:

上面的圖中樣子還不錯的樣子,同時他們還是同一個頁面,這下就很nice了,又可以少寫一個界面了。
按照前面兩期我們的東西綜合起來,我們需要先把CSS、JS、圖片等東西,扔到我們的靜態目錄中。如下圖所示:

接著我們把登錄的html的頁面的東西,全部放到login.jsp中。如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%-- 上面這兩行是java代碼的引用 --%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<script type="text/javascript" src="/static/js/jquery-3.1.1.min.js"></script>
<head>
<title>倉庫管理系統→登錄</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="/static/js/login.js"></script>
<link href="/static/css/login2.css" rel="stylesheet" type="text/css"/>
</head>
<html>
<body>
<h1>倉庫管理系統登陸注冊<sup>2016</sup></h1>
<div class="login" style="margin-top:50px;">
<div class="header">
<div class="switch" id="switch"><a class="switch_btn_focus" id="switch_qlogin" href="javascript:void(0);"
tabindex="7">快速登錄</a>
<a class="switch_btn" id="switch_login" href="javascript:void(0);" tabindex="8">快速注冊</a>
<div class="switch_bottom" id="switch_bottom" style="position: absolute; width: 64px; left: 0px;"></div>
</div>
</div>
<div class="web_qr_login" id="web_qr_login" style="display: block; height: 235px;">
<!--登錄-->
<div class="web_login" id="web_login">
<div class="login-box">
<div class="login_form">
<form action="<%=request.getContextPath()%>/userAction/login" name="loginform"
accept-charset="utf-8" id="login_form" class="loginForm"
method="post"><input type="hidden" name="did" value="0"/>
<input type="hidden" name="to" value="log"/>
<div class="uinArea" id="uinArea">
<label class="input-tips" for="u">帳號:</label>
<div class="inputOuter" id="uArea">
<input type="text" id="u" name="loginId" class="inputstyle"/>
</div>
</div>
<div class="pwdArea" id="pwdArea">
<label class="input-tips" for="p">密碼:</label>
<div class="inputOuter" id="pArea">
<input type="password" id="p" name="pwd" class="inputstyle"/>
</div>
</div>
<div style="padding-left:50px;margin-top:20px;">
<input type="submit" value="登 錄"
style="width:150px;"
class="button_blue"/></div>
</form>
</div>
</div>
</div>
<!--登錄end-->
</div>
<!--注冊-->
<div class="qlogin" id="qlogin" style="display: none; ">
<div class="web_login">
<form name="form2" id="regUser" accept-charset="utf-8" action="<%=request.getContextPath()%>/userAction/reg"
method="post">
<input type="hidden" name="to" value="reg"/>
<input type="hidden" name="did" value="0"/>
<ul class="reg_form" id="reg-ul">
<div id="userCue" class="cue">快速注冊請注意格式</div>
<li>
<label for="user" class="input-tips2">用戶名:</label>
<div class="inputOuter2">
<input type="text" id="user" name="loginId" maxlength="16" class="inputstyle2"/>
</div>
</li>
<li>
<label for="user" class="input-tips2">姓名:</label>
<div class="inputOuter2">
<input type="text" id="name" name="name" maxlength="16" class="inputstyle2"/>
</div>
</li>
<li>
<label for="passwd" class="input-tips2">密碼:</label>
<div class="inputOuter2">
<input type="password" id="passwd" name="pwd" maxlength="16" class="inputstyle2"/>
</div>
</li>
<li>
<label for="passwd2" class="input-tips2">確認密碼:</label>
<div class="inputOuter2">
<input type="password" id="passwd2" name="" maxlength="16" class="inputstyle2"/>
</div>
</li>
<li>
<label for="cellNumber" class="input-tips2">手機號:</label>
<div class="inputOuter2">
<input type="text" id="cellNumber" name="cellNumber" maxlength="18" class="inputstyle2"/>
</div>
</li>
<li>
<label for="sex" class="input-tips2">性別:</label>
<div class="inputOuter2">
<input type="text" id="sex" name="sex" maxlength="18" class="inputstyle2"/>
</div>
</li>
<li>
<label for="age" class="input-tips2">年齡:</label>
<div class="inputOuter2">
<input type="age" id="age" name="age" maxlength="18" class="inputstyle2"/>
</div>
</li>
<li>
<div class="inputArea">
<input type="button" id="reg" style="margin-top:10px;margin-left:85px;" class="button_blue"
value="同意協議并注冊"/> <a href="#" class="zcxy" target="_blank">注冊協議</a>
</div>
</li>
<div class="cl"></div>
</ul>
</form>
</div>
</div>
<!--注冊end-->
</div>
<div class="jianyi">*推薦使用ie8或以上版本ie瀏覽器或Chrome內核瀏覽器訪問本站</div>
</body>
</html>
上面的網頁代碼中的東西,我們也可以不求甚解,只要會調用就行。調用地址是在我們的form表單的action那里填寫我們的服務器地址。這里我們甚至可以做前后端分離,用純粹的html+js來調用Api接口實現前后端分離。
action="<%=request.getContextPath()%>/userAction/reg" method="post"
<%=request.getContextPath()%> 這是指向我們應用的根路徑
mothod是說明我們請求的方式,我們這里才用了post,至于其他的方法就不一一介紹了,詳細信息請百度查找“ http請求 ”
form表單中,每個input的name我們需要和后端的接口那邊的字段對應。
當我們的字段對應后,spring可以自動把請求的內容轉換為適應的對象。
小提示:我們可以直接debug我們的程序,只要取消斷點程序就可以順序執行,加入斷點只要程序流轉到那里,他就會自動調試。
當然,我們的jsp寫完后,我們需要給我們的表單請求那里指定請求路徑。由于上面我已經指定了路徑,所以我們需要在對應的路徑創建請求的接口(實際開發中都是先寫好請求接口,再讓程序調用。由于我這里是提前寫好的,所以這里我們得照著路徑寫代碼)。
我們在Controller目錄下創建一個UserController類,代碼內容如下:
package cn.acheng1314.mvc.controller;
import cn.acheng1314.domain.ResponseObj;
import cn.acheng1314.domain.User;
import cn.acheng1314.exception.*;
import cn.acheng1314.service.serviceImpl.UserServiceImpl;
import cn.acheng1314.utils.GsonUtils;
import cn.acheng1314.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 用戶請求相關控制器
* <br/>Created by acheng on 2016/9/26.
*/
@Controller
@RequestMapping("/userAction")
public class UserController {
@Autowired
private UserServiceImpl userService; //自動載入Service對象
private ResponseObj responseObj; //bean對象
/**
* 為什么返回值是一個ModelAndView,ModelAndView代表一個web頁面<br/>
* setViewName是設置一個jsp頁面的名稱
* @param req http請求
* @param user 發起請求后,spring接收到請求,然后封裝的bean數據
* @return 返回一個web頁面
* @throws Exception
*/
@RequestMapping(value = "/reg", method = RequestMethod.POST)
public ModelAndView reg(HttpServletRequest req, User user) throws Exception {
ModelAndView mav = new ModelAndView(); //創建一個jsp頁面對象
mav.setViewName("home"); //設置JSP文件名
if (null == user) {
mav.addObject("message", "用戶信息不能為空!"); //加入提示信息,在jsp中我們直接使用${對象名稱}就能獲取對應的內容
return mav; //返回頁面
}
if (StringUtils.isEmpty(user.getName()) || StringUtils.isEmpty(user.getPwd())) {
mav.addObject("message", "用戶名或密碼不能為空!");
return mav;
}
if (null != userService.findUser(user)) {
mav.addObject("message", "用戶已經存在!");
return mav;
}
try {
userService.add(user);
} catch (Exception e) {
e.printStackTrace();
mav.addObject("message", "錯誤:用戶其他信息錯誤");
return mav;
}
mav.addObject("code", 110);
mav.addObject("message", "恭喜。注冊成功");
req.getSession().setAttribute("user", user);
return mav;
}
/**
* 登錄接口
* @param req
* @param user
* @return
*/
@RequestMapping(value = "/login", method = RequestMethod.POST, produces = {
"application/json; charset=utf-8"})
@ResponseBody
public ModelAndView login(HttpServletRequest req, User user) {
ModelAndView mav = new ModelAndView("home");
String result;
if (null == user) {
responseObj = new ResponseObj<User>();
responseObj.setCode(ResponseObj.EMPUTY);
responseObj.setMsg("登錄信息不能為空");
result = GsonUtils.gson.toJson(responseObj); //轉換的json數據
mav.addObject("result", result);
return mav; //返回頁面
}
if (StringUtils.isEmpty(user.getLoginId()) || StringUtils.isEmpty(user.getPwd())) {
responseObj = new ResponseObj<User>();
responseObj.setCode(ResponseObj.FAILED);
responseObj.setMsg("用戶名或密碼不能為空");
result = GsonUtils.gson.toJson(responseObj);
mav.addObject("result", result);
return mav;
}
//查找用戶
User user1 = userService.findUser(user);
if (null == user1) {
responseObj = new ResponseObj<User>();
responseObj.setCode(ResponseObj.EMPUTY);
responseObj.setMsg("未找到該用戶");
result = GsonUtils.gson.toJson(responseObj);
} else {
if (user.getPwd().equals(user1.getPwd())) {
responseObj = new ResponseObj<User>();
responseObj.setCode(ResponseObj.OK);
responseObj.setMsg(ResponseObj.OK_STR);
result = GsonUtils.gson.toJson(responseObj);
} else {
responseObj = new ResponseObj<User>();
responseObj.setCode(ResponseObj.FAILED);
responseObj.setMsg("用戶密碼錯誤");
result = GsonUtils.gson.toJson(responseObj);
}
}
mav.addObject("result", result);
return mav;
}
}
當然很多數據效驗我們不能只在后端做,我們需要將數據檢查的粒度細化。
不但要在后端做,而且我們的前端頁面也要做的,比如說手機號、郵箱帳號、用戶名規則等等,用的最多的也就是web頁面上面拿到數據用js來判斷,使用正則表達式來判斷是否符合標準。
具體的js我也就不寫了,因為我也不是很了解JS,只能對著別人寫的自己來做修改==
好的,我們現在已經把東西都弄完了,debug開啟程序,然后加入斷點調試。運行結果如下:

這樣我們現在能拿到對應的數據,并且在Controller中加入了數據校驗。同時,我們的web頁面中也加入了js驗證。
現在我們的注冊頁面也可以了,功能也有了。既然如此,我們應該接著把登錄頁面做成功,但是我們已經有了這個的思路,那么剩下的只需要依樣畫瓢就能完成。
具體的東西,都已經在后面的代碼中貼出來了。詳情請看github:
項目地址:點擊訪問github
總結:
- URL生成
- 注冊登錄完成
- 簡單的前端驗證(在代碼包中可以看到)
- form表單提交
- http請求
- 功能模塊分析
- 流程圖(使用xmind制作)
下期預告:完整的后臺主頁,前端使用json數據,列表數據分頁。