SSM 重構(gòu)注冊登陸界面

文章來自我的博客

正文之前

之前有做過一個練手的商品管理的小項目洪燥,然后用 SSM 重構(gòu)了乳乌,接下來又做了一個模擬注冊登錄的界面,然后前兩天用 SSM 重構(gòu)了這個項目的后臺代碼汉操,修改了一點前端頁面,后臺功能不變

接下來還有在此基礎上做新的功能:保持登陸狀態(tài)磷瘤,查看個人信息等,然后把注冊登陸界面整合至商品管理的項目采缚,一步一步擴大

正文

1. 項目截圖

下面的文檔中有給出截圖

2. 功能實現(xiàn)

  1. 注冊、登陸

常規(guī)的注冊登陸操作

  1. 驗證碼

輸出驗證碼糊识,單擊驗證碼圖片可刷新

  1. 驗證用戶

注冊是驗證用戶名、電話號碼和郵箱是否已被注冊赂苗,登陸時驗證用戶是否已注冊以及密碼是否正確贮尉,兩個過程中都有檢測驗證碼的準確性

3. 具體說明

我還是放上項目的 README 文檔吧:

Registration-login-interface2

Version 0.1

使用 SSM 框架來對原先的 Registration-login-interface 進行重構(gòu)拌滋,頁面做細微改動猜谚,后臺使用框架,來達到同樣的效果:

0.1 版本是使用框架進行重構(gòu)昌犹,接下來的 0.2 版本將會是添加一些功能:用戶保持登陸狀態(tài),添加一張 SQL 表來存放用戶信息斜姥,并在頁面中進行個人信息添加和修改

1. 文件結(jié)構(gòu)

關于建包和創(chuàng)建哪些類,不多說铸敏,直接上一整個項目的圖:

2. 配置文件(config 包)

將 Spring 和 MyBatis 整合的方式,在之前的 new-p-mmybatis-spring 官方文檔 中都能找到答案杈笔,這里直接給出配置:

數(shù)據(jù)庫信息(db.properties):

jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/user
jdbc.username = xxx(你自己的用戶名)
jdbc.password = xxx(你自己的密碼)

spring-mvc.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 組件掃描 -->
    <context:component-scan base-package="controller"/>
    <context:component-scan base-package="service"/>

    <!-- 注解驅(qū)動 -->
    <mvc:annotation-driven/>

    <!-- 配置視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 這兩行代碼是為了不讓靜態(tài)資源被 servlet 攔截 -->
    <mvc:resources mapping="/image/**" location="image"/>
    <mvc:resources mapping="../../css/**" location="css"/>
</beans>

spring-mybatis.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 將數(shù)據(jù)庫信息配置在外部文件中蒙具,使用占位符來代替具體信息的配置 -->
    <context:property-placeholder location="classpath:config/db.properties"/>

    <!-- 配置數(shù)據(jù)源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- sqlSessionFactory 的配置,這是基于 MyBatis 的應用的核心 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 使用上面定義的數(shù)據(jù)源來進行配置 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 查找下面指定的類路徑中的映射器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 定義 Mapper 配置器的位置 -->
        <property name="basePackage" value="mapper"/>
    </bean>

    <!-- 之后要用到的兩個 Bean -->
    <bean id="exceptionService" class="service.impl.ExceptionServiceImpl"/>
    <bean id="verifyCode" class="util.VerifyCode"/>
</beans>

3. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/config/spring/spring-mybatis.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/spring/spring-mvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
</web-app>

第 2 步中配置的兩個文件作為上下文配置信息,最后的 url 映射是 xxx.action 的形式

4. 實體類(User.java)

為了節(jié)省篇幅鞠呈,這里不給出實體類代碼,和 Registration-login-interface 中的實體類是一樣的

5. 自定義異常

自定義的異常是調(diào)用父類方法來實現(xiàn)的蚁吝,因用戶注冊或登陸時輸入有誤而拋出

public class UserException extends Exception {
//自定義異常
public UserException(String message) {
super(message);
}
}

6. 映射器

MyBatis-Spring 提供的 MapperFactoryBean 能夠進行動態(tài)代理,能夠?qū)?shù)據(jù)映射器接口注入到 Service 層中的 Bean 里怀伦,注意,一定要是接口房待,不能是實現(xiàn)類,所以我們這里寫了一個 UserMapper:

public interface UserMapper {
    void addUser(User user);
    User findUserByName(String username);
    User findUserByPhone(String phone);
    User findUserByEmail(String email);
}

映射器接口對應著一個同名的 XML 映射器文件文件:UserMapper.xml

這個映射器中寫的是 SQL 語句桑孩,這里面有四句框冀,添加流椒,按照名稱明也、電話號碼和郵箱進行查找宣虾,映射文件的命名空間(namespace)對應著映射器接口的名稱温数,SQL 語句的 id 對應著接口中的方法,不能有誤

<mapper namespace="mapper.UserMapper">
    <insert id="addUser" parameterType="domain.User">
      INSERT INTO user(username,password,phone,email)
      VALUES (#{username}, #{password}, #{phone}, #{email})
    </insert>

    <select id="findUserByName" parameterType="String" resultType="domain.User">
        SELECT * FROM user WHERE username = #{username}
    </select>

    <select id="findUserByPhone" parameterType="String" resultType="domain.User">
        SELECT * FROM user WHERE phone = #{phone}
    </select>

    <select id="findUserByEmail" parameterType="String" resultType="domain.User">
        SELECT * FROM user WHERE email = #{email}
    </select>
</mapper>

6. 驗證碼

SSM 版本的驗證碼沒有變化撑刺,還是 Registration-login-interface 中的驗證碼,不做更改

7. Service 層

Service 層有兩個接口次员,一個是關于注冊和登陸的:

public interface UserService {
    public void addUser(User user) throws UserException;
    public void login(User user) throws UserException;
}

另一個是檢測注冊和登陸過程中的錯誤情況:

@Service
public interface ExceptionService {

    //_user 是從數(shù)據(jù)庫中查找出的記錄败许,user 是用戶輸入
    public void loginException(User user, User db_user) throws UserException;

    public void addUserException1(User user) throws UserException;

    public void addUserException2(User user) throws UserException;
}

先寫 ExceptionService 的實現(xiàn)淑蔚,在注冊和登陸過程中要使用:

    //先創(chuàng)建 Bean,接下來會用到
    private final UserMapper userMapper;

    @Autowired
    public ExceptionServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    
    //先判斷輸入格式是否有誤
    public void addUserException1(User user) throws UserException{
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()){
            throw new UserException("用戶名不能為空");
        }else if (user.getUsername().length() < 5 || user.getUsername().length() > 15){
            throw new UserException("用戶名必須為5-15個字符");
        }

        if (user.getPassword() == null || user.getPassword().trim().isEmpty()){
            throw new UserException("密碼不能為空");
        }else if (user.getPassword().length() < 5 || user.getPassword().length() > 15){
            throw new UserException("密碼必須為5-15個字符");
        }

        if (user.getPhone() == null || user.getPhone().trim().isEmpty()){
            throw new UserException("電話號碼不能為空");
        }

        if (user.getEmail() == null || user.getEmail().trim().isEmpty()){
            throw new UserException("郵箱不能為空");
        }
    }

    //再判斷輸入的信息是否已被注冊
    public void addUserException2(User user) throws UserException{
        //這三者都必須是唯一的
        if (userMapper.findUserByName(user.getUsername()) != null){
            throw new UserException("該用戶名已被注冊");
        } else if (userMapper.findUserByPhone(user.getPhone()) != null){
            throw new UserException("該電話號碼已被注冊");
        } else if (userMapper.findUserByEmail(user.getEmail()) != null){
            throw new UserException("該郵箱已被注冊");
        }
    }

    //登入檢測
    public void loginException(User user, User db_user) throws UserException {

        if(db_user == null){
            throw new UserException("該用戶不存在");
        }
        if(!user.getPassword().equals(db_user.getPassword())){
            throw new UserException("密碼錯誤");
        }
    }

    //驗證碼檢測
    @Override
    public void verifyCodeException(String inputVerifyCode, String code) throws UserException {
        if (inputVerifyCode == null || inputVerifyCode.trim().isEmpty()){
            throw new UserException("驗證碼不能為空");
        } else if (inputVerifyCode.length() != 4){
            throw new UserException("驗證碼長度應為 4 位");
        } else if (!inputVerifyCode.equals(code)){
            throw new UserException("驗證碼錯誤");
        }
    }

然后是 UserService 的實現(xiàn):

    //先是用構(gòu)造器注入來創(chuàng)建 UserMapper 和 ExceptionService 兩個 Bean
    private final UserMapper userMapper;

    private final ExceptionService exceptionService;

    @Autowired
    public UserServiceImpl(UserMapper userMapper, ExceptionService exceptionService) {
        this.userMapper = userMapper;
        this.exceptionService = exceptionService;
    }
    
    public void addUser(User user) throws UserException {
        //先判斷用戶的輸入是否有錯
        exceptionService.addUserException1(user);
        //再判斷用戶的信息是否已被注冊
        exceptionService.addUserException2(user);
        userMapper.addUser(user);
    }
    
    //根據(jù)用戶輸入名字去數(shù)據(jù)庫查找有沒有這個用戶醋寝,如果沒有带迟,就會拋出異常
    public void login(User user) throws UserException {
        User db_user = userMapper.findUserByName(user.getUsername());
        exceptionService.loginException(user, db_user);
    }

可能有人會覺得為什么登陸的方法沒有返回值,其實如果登入成功仓犬,也就是沒有拋出異常,在 Controller 中就可以接著執(zhí)行后面的方法搀继,如果用戶名或密碼錯誤,是會拋出異常叽躯,中斷程序的

8. Controller

到了關鍵的一步,Controller 負責處理 DispatcherServlet 分發(fā)的請求:

首先是使用構(gòu)造器注入來創(chuàng)建三個 Bean:

    private final UserService userService;

    private final VerifyCode verifyCode;

    private final ExceptionService exceptionService;

    @Autowired
    public UserController(UserService userService, VerifyCode verifyCode, ExceptionService exceptionService) {
        this.userService = userService;
        this.verifyCode = verifyCode;
        this.exceptionService = exceptionService;
    }

userService 就是用于注冊和登陸的点骑,verifyCode 就是用于得到驗證碼,exceptionService 是用來檢測注冊和登陸過程中是否出現(xiàn)錯誤

在注冊和登陸之前黑滴,都需要得到帶有表單的頁面:

    //在注冊之前需要先得到注冊的界面
    @RequestMapping("/preAdd")
    public ModelAndView preAdd(){
        return new ModelAndView("addUser");
    }
    
    //同樣的,需要先得到界面
    @RequestMapping("preLogin")
    public ModelAndView preLogin(){
        return new ModelAndView("login");
    }

然后是注冊的過程馋嗜,先調(diào)用 addUser() 方法,如果用戶注冊的時候出現(xiàn)了問題葛菇,比如說用戶名、電話號碼或者郵箱已被注冊眯停,就直接拋出異常卿泽,就沒有執(zhí)行驗證碼驗證的方法了,如果沒問題齐邦,就接著檢測驗證碼輸入措拇,將表單輸入與驗證碼文本進行比較

    @RequestMapping("/addUser")
    public ModelAndView addUser(User user, HttpServletRequest request){
        ModelAndView modelAndView;
        //如果下面的 try 語句塊沒有拋出異常,則返回 addUserSuccessful.jsp
        modelAndView = new ModelAndView("addUserSuccessful");
        try{
            //先調(diào)用添加用戶的方法丐吓,看看有沒有因為不符規(guī)定的輸入而導致異常拋出
            userService.addUser(user);
            //然后再看有沒有因為驗證碼錯誤而導致異常拋出
            exceptionService.verifyCodeException(request.getParameter("verifyCode"), verifyCode.getText());
        } catch (UserException e){
            //如果捕獲異常券犁,就帶著異常信息返回注冊界面
            modelAndView = new ModelAndView("addUser");
            modelAndView.addObject("message", e.getMessage());
        }
        return modelAndView;
    }

登陸的過程粘衬,也是先先檢查用戶輸入信息是否有誤荞估,再檢查驗證碼信息

    //登陸的邏輯和上面是一樣的
    @RequestMapping("/login")
    public ModelAndView login(User user, HttpServletRequest request) {
        ModelAndView modelAndView;
        modelAndView = new ModelAndView("loginSuccessful");
        try {
            userService.login(user);
            exceptionService.verifyCodeException(request.getParameter("verifyCode"), verifyCode.getText());
        } catch (UserException e){
            modelAndView = new ModelAndView("login");
            modelAndView.addObject("message", e.getMessage());
        }
        return modelAndView;
    }

最后是關于輸出驗證碼圖片的操作:

    //得到驗證碼色难,然后用于 jsp 文件的 <img> 標簽的 src 屬性中
    @RequestMapping("/getVerifyCode")
    public void setVerifyCode(HttpServletResponse response)
            throws IOException{
        //設置響應格式
        response.setContentType("image/jpg");
        //得到圖片
        BufferedImage image = verifyCode.getImage();
        //輸出
        verifyCode.output(image, response.getOutputStream());
    }
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末等缀,一起剝皮案震驚了整個濱河市尺迂,隨后出現(xiàn)的幾起案子噪裕,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苍凛,死亡現(xiàn)場離奇詭異兵志,居然都是意外死亡想罕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門笙瑟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逮走,“玉大人今阳,你說我怎么就攤上這事墓臭⊙矗” “怎么了膝舅?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵仍稀,是天一觀的道長。 經(jīng)常有香客問我遥巴,道長铲掐,這世上最難降的妖魔是什么值桩? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任奔坟,我火速辦了婚禮蛀蜜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘磅摹。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布碍彭。 她就那樣靜靜地躺著庇忌,像睡著了一般舰褪。 火紅的嫁衣襯著肌膚如雪占拍。 梳的紋絲不亂的頭發(fā)上晃酒,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天崔兴,我揣著相機與錄音浊闪,去河邊找鬼搁宾。 笑死盖腿,一個胖子當著我的面吹牛损同,可吹牛的內(nèi)容都是我干的膏燃。 我是一名探鬼主播组哩,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罐栈!你這毒婦竟也來了泥畅?” 一聲冷哼從身側(cè)響起位仁,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤凌外,失蹤者是張志新(化名)和其女友劉穎涛浙,沒想到半個月后轿亮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體我注,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡励七,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年掠抬,在試婚紗的時候發(fā)現(xiàn)自己被綠了校哎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闷哆。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡劣坊,死狀恐怖屈留,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锐想,我是刑警寧澤赠摇,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布烫罩,位于F島的核電站洽故,受9級特大地震影響时甚,放射性物質(zhì)發(fā)生泄漏荒适。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望质欲。 院中可真熱鬧嘶伟,春花似錦榨惠、人聲如沸赠橙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至速兔,卻和暖如春涣狗,著一層夾襖步出監(jiān)牢的瞬間舒憾,已是汗流浹背镀迂。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工探遵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饰序。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓求豫,卻偏偏與公主長得像诉稍,于是被迫代替她去往敵國和親杯巨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理仍源,服務發(fā)現(xiàn)笼踩,斷路器,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 很有意思挟冠,人類以貌取人的條件是顏值越高機會就會越多袍睡,而影片中的著名學府同樣也是以貌取人斑胜,卻因長的丑陋(人類認為的)...
    糅文愈心閱讀 1,288評論 0 1
  • gitignore需要忽略子目錄中伪窖,擁有某后綴的文件。用**代表所有子目錄例如,我要忽略以iml結(jié)尾的文件簇宽,可以如下所示
    java修煉閱讀 24,674評論 2 6
  • 高中階段能記起來的讀過的書(我卑微存在的勉強證明 雖然讀了這么多好的壞的亂七八糟的書譬嚣,可頭腦依舊沒有開化): 沈復...
    愛寫點文字的女孩閱讀 289評論 0 0
  • “習武之人全在勤拜银!天遠遭垛,快點起來練武了锯仪!已經(jīng)五更了!”師父這幾句話雖未用內(nèi)功傳音小腊,卻也把與他一門之隔的梁天遠從夢境...
    湘潭大學三翼傳媒閱讀 708評論 1 2