[手把手教程][JavaWeb]优雅的SSM应用(三)

[手把手教程][JavaWeb]优雅的SSM应用(三)

文章正式改名为:[手把手教程][JavaWeb]优雅的SSM应用

这几天一直在踩坑,为什么这么说呢,主要是一直自己没找到优雅的方式来实现一些东西。

虽然说前面也做了一些功能模块,但是总感觉不对劲,毕竟也是刚转做后端。

为了方便手机端用户,尽量使用简单的markdown语法和简单的页面结构。

后面朋友给了我一些他们公司同事写的demo,虽然说不上是牛逼的作品,但是确实符合我现在的需要。毕竟人家的实现方式也是经过实战项目演练出来的。

工具

  • IDE为idea15
  • JDK环境为1.8
  • maven版本为maven3
  • Mysql版本为5.5.27
  • Tomcat版本为7.0.52
  • 流程图绘制(xmind)

本期目标

  • 仓库管理系统的登录注册模块实现
  • 其他一些开发细节的体现
  • 功能模块分层设计的具体实现

其他

  • 我这姑且算是文章吧,文章都是先用有道云笔记写的,然后在简书上面查看有没有冲突,最后再放到稀土掘金上面
  • 但是稀土掘金上面文章出问题了,反馈上去也没能解决,本来想抓包看看他们的数据的,后面还是没做
  • ···其他想说的就太多了,但都是不是今天的主题。

注册

首先,我们webapp要实现用户登录,必须得能新建用户。所以,我们先把注册用户放在前面。

  • 预期功能:
    • 打开注册页面
    • 填写注册信息
    • 点击注册
    • 显示注册后的提示信息

有了功能后,我们就能大概明白我们是想要一个什么样子的注册模块了。

  • 一个web注册页面
  • web页面能进行基本的数据效验
  • 服务器能存储用户的注册信息
  • 注册动作完成后,返回提示页面。

一般的,我们在开发中,有了大概样子的功能模块,我们需要整理一下业务流程和程序执行流程(在企业开发中,有项目经理的话,一般这些都是他们整理出来的,我们只需要开发实现就行。)经过一番挠头,大概的流程图如下所示:

ssm应用三-注册流程
ssm应用三-注册流程

上图说明:

  • 我们在web页面完成注册信息的填写后,我们需要在web页面做一些基本的数据效验。当然后面我们会演示。
  • 注册信息通过基本的验证后,我们直接提交到服务器,tomact → servelt → spring 。我们的后端程序,一切都被spring接管了,所以,我们需要在spring中完成这些功能。
  • spring和外界通信,我们都是在Controller中完成。所以我们在Controller中处理数据。
  • 当数据通过了Controller中的校验后,我们需要在Controller中来查找数据库是否存在同样的用户名,通用的数据操作流程如:Controller → Service → Dao
  • 前面我们提到过,Service是为我们的程序提供服务的,我们尽量每个Service对应一个Dao,这样我们只需要提供单一的数据驱动,在外层进行业务组装,这样就能达到我们的目的,同样的,我们这样也能将程序解耦,以后的维护也就相对简单了。

好的,我们上面已经把思路想明白了。现在我们接着就开始实战。

  • 生成注册页面的连接。

我们要生成一个连接,经过查找资料,我们知道我们需要创建一个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文件中填写对应的代码就行了。

好的,基本的东西我们都说了,那么我们先去百度找一个登录界面(一定要能看,不能那啥太直接的粗糙的东西,毕竟我们都是有品位的人)。如下图:

ssm应用三-登录注册页面
ssm应用三-登录注册页面

上面的图中样子还不错的样子,同时他们还是同一个页面,这下就很nice了,又可以少写一个界面了。

按照前面两期我们的东西综合起来,我们需要先把CSS、JS、图片等东西,扔到我们的静态目录中。如下图所示:

ssm应用三-登录注册静态资源
ssm应用三-登录注册静态资源

接着我们把登录的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开启程序,然后加入断点调试。运行结果如下:

ssm应用三-注册页面和调试
ssm应用三-注册页面和调试

这样我们现在能拿到对应的数据,并且在Controller中加入了数据校验。同时,我们的web页面中也加入了js验证。

现在我们的注册页面也可以了,功能也有了。既然如此,我们应该接着把登录页面做成功,但是我们已经有了这个的思路,那么剩下的只需要依样画瓢就能完成。

具体的东西,都已经在后面的代码中贴出来了。详情请看github:

项目地址:点击访问github

总结:

  • URL生成
  • 注册登录完成
  • 简单的前端验证(在代码包中可以看到)
  • form表单提交
  • http请求
  • 功能模块分析
  • 流程图(使用xmind制作)

下期预告:完整的后台主页,前端使用json数据,列表数据分页。

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

推荐阅读更多精彩内容