1. 程式人生 > >【Spring+SpringMVC+Mybatis】利用SSM整合,完成使用者登入、註冊、修改密碼系統

【Spring+SpringMVC+Mybatis】利用SSM整合,完成使用者登入、註冊、修改密碼系統

近年來,由於Struts2+Hibernate3+Spring3,這套SSH框架,Struts2屢次爆出安全漏洞,Hibernate就只會推行它HQL那套而越來越遠離SQL查詢關係資料庫的本質,所以Spring+SpringMVC+Mybatis這套SSM框架悄然興起,現階段在Javaee領域,有種新專案必選SSM的趨勢。本文將利用一個簡單的例子,具體如下圖所示,其實也就是把《【Struts2+Hibernate3+Spring3】利用SSH整合,完成列印使用者表,使用者登入、註冊、修改密碼系統》(點選開啟連結)中的SSH例子再用SSM再做一次,同時檢視儘可能地不雜糅其它技術,以最短的程式碼,給大家展示Spring、SpringMVC、Mybatis三者整合的例子。


一、SSM的下載和配置

在Eclipse新建一個JavaEE的Dynamic Web Project估計已經不用說了,接下來我就不用什麼Maven了,自己配好所有必須的jar包,具體如下。

1、Spring和SpringMVC的下載和配置

其實Spring和SpringMVC所用的jar包都是相同的,畢竟Spring他希望自己一套吃遍Java的所有領域,但Spring做Java和xml互動、近年來SpringMVC做Java和JSP的互動做得最為突出,所以流行起來了。

Spring3.x的使用首先需要commons-logging-1.2.jar這玩意,這個commons-logging-1.2.jar是所有jar的前提,不然,你的java應用只有jar的話,spring根本啟動不了,最直接的表現是配置了spring的javaee應用的tomcat啟動不來。


所以,你要先下載commons-logging-1.2.jar。這玩意直接在Apache Tomcat的官網有,不是很明白為何不直接搞到Tomcat裡面。


下載之後解壓,直接取走裡面的commons-logging-1.2.jar到你的java應用。

commons-logging-1.2-javadoc.jar是個API說明文件,並沒有什麼卵用。


接下來,才是下載Spring3.x。Spring的包全部放到http://repo.spring.io/裡面了,在Spring的官網,http://spring.io你只會看到你並希望Maven下載和一大堆說明文件,頂多是最新版Github託管而已。

進入了spring的資源庫之後,如下圖,找到libs-release-local(這spring都不知道怎麼想的,堂堂的javaee大廠,資源庫裡面的東西竟然不是按a-z排的)->org->springframework->spring->3.2.18 release然後選擇右上角的download,下載Spring3.x的最終穩定版。


下載之後解壓,在libs中,取走所有最終應用,關於API說明*-javadoc.jar、原始碼*-sources.jar完全可以不需要。

2、JDBC和Mybatis的下載

JDBC請選擇合適自己資料庫的版本,本文用Mysql做例子,所以選擇的是Mysql的JDBC。

你首先需要兩個jar,一個是連線Mysql必須的jar,這裡以Mysql做例子,Orcale等資料庫則換成相應的jar包即可,可以到Mysql的官網下載:https://dev.mysql.com/downloads/connector/j/,下載之後取走其中的mysql-connector-java-5.1.44-bin.jar到你的工程目錄,一般在工程目錄新建一個lib,放這些包。


然後下載Mybatis,最新的Mybatis是放在Github託管的,網址:https://github.com/mybatis/mybatis-3/releases,同樣取走裡面的核心jar,放到你的工程目錄的WEB-INF\lib下。


3、Mybatis和Spring互動包

最後補上這個jar就OK了。


整合之後WEB-INF\lib資料夾如下所示:


二、目錄結構和所使用的資料庫表

按照上述過程配好在WEB-INF\lib配好jar包之後,先貼上我最終完工的工程目錄結構:


還有我使用的資料庫表,還是這張早已舉個栗子舉爛的Mysql中test資料庫的User使用者表,隨便開個Mysql,建立張user表,資料庫test弄出來的。


三、配置檔案xml的編寫

1、我們先從這個Javaee工程的總配置檔案web.xml看起,所有Javaee工程必有這個檔案。在這個檔案中,主要是宣告使用SpringMVC、Spring還有這個網站主要使用UTF-8編碼,避免亂碼。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">
	<!-- 啟用SpringMVC -->
	<servlet>
		<servlet-name>SpringMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<!-- 指明Spring配置的初始化檔案 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
	</context-param>
	<!-- 字元編碼過濾器 -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/</url-pattern>
	</filter-mapping>
</web-app>

這裡的web.xml的初始化,不同於之前《【Spring+Mybatis】Spring整合Mybatis》(點選開啟連結)中,指明在 Java工程Spring的核心配置檔案applicationContext.xml所在目錄時,在contextConfigLocation的值只寫一個applicationContext.xml就行,必須寫明/WEB-INF/applicationContext.xml,不完全寫明,Javaee工程找applicationContext.xml會直接去網站根目錄WebContent找,肯定找不到,同時會出現org.springframework.beans.factory.BeanCreationException之類的錯誤

2、接下來先看SpringMVC-servlet.xml,命名只能這樣寫,畢竟在web.xml,指明的servlet-name就是SpringMVC,這個檔案我在《【SpringMVC】Helloworld》(點選開啟連結)已經詳細寫過了,還是那句話,這篇文章主要是介紹SSM整合的,要是每個技術都寫一次,就顯得沒有重點了。

這裡除了要求SpringMVC在actios找servlet以外,同時要求Spring掃描Service層,是因為在action用到Service的類中的方法和資料庫打交道,所以必須要求actions層注入Service。同時掃描test.actions和test.services。

<?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:p="http://www.springframework.org/schema/p"  
    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-2.5.xsd    
    http://www.springframework.org/schema/context     
    http://www.springframework.org/schema/context/spring-context-2.5.xsd    
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
  
    <context:component-scan base-package="test.actions" />  
    <context:component-scan base-package="test.services" />  
  
    <bean  
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/views/" />  
        <property name="suffix" value=".jsp" />  
    </bean>  
  
</beans>  

3、然後是Spring的核心配置檔案applicationContext.xml了,這裡和《【Spring+Mybatis】Spring整合Mybatis》(點選開啟連結)同樣,同時整合JDBC和Mybatis,利用Spring配置資料來源,同時指出Mybatis的核心配置檔案是/WEB-INF/configuration.xml。這裡還利用到Spring整合SpringMVC的自動註解功能,可以用一個@將原來的Spring必須要求的private私有變數+getter+setter,精簡到一個註解+private私有變數即可。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd ">
	<!-- Spring連線的JDBC資料來源 -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url"
			value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useOldAliasMetadataBehavior=true" />
		<property name="username" value="root" />
		<property name="password" value="root" />
	</bean>
	<!-- 指出Mybatis的核心配置檔案,關於資料庫表和Java檔案的對映寫在裡面 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="/WEB-INF/configuration.xml"></property>
	</bean>
	<!-- 指出資料庫介面方法所在的包 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
		autowire="byName">
		<property name="basePackage" value="test.dao" />
		<property name="sqlSessionFactory" ref="sqlSessionFactory" />
	</bean>
	<!-- 啟動Spring MVC的註解功能,完成請求和註解POJO的對映 -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
</beans> 

這裡/WEB-INF/configuration.xml也必須完全寫明,不能只寫configuration.xml,不然就會出現org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.mybatis.spring.mapper.MapperScannerConfigurer#0' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Cannot resolve reference to bean 'sqlSessionFactory' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/configuration.xml]的報錯,無法啟動tomcat,具體如下圖所示:

4、最後就是Mybatis的配置檔案configuration.xml了,由於Spring的存在,讓configuration.xml可以變得非常簡單,不用像《【Mybatis】Helloworld》(點選開啟連結)裡面寫得這麼長,指出資料庫和Java的對映關係Mapper的所在地即可。

<?xml version="1.0" encoding="UTF-8"?>    
<!DOCTYPE configuration      
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"      
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 指明在user這個表中所包含常用sql方法,test/mapper/User.xml是一個指明java方法和sql語法聯絡的xml檔案 -->
	<mappers>
		<mapper resource="test/mapper/User.xml" />
	</mappers>
</configuration>   

然後順手在test.mapper包下新建一個User.xml。

四、工程核心檔案的編寫

經歷了上面一大堆配置檔案終於弄好整個Spring+SpringMVC+Mybatis的配置了,接下來開始分門別類地分層嚴格遵循MVC的思想編寫整個Javaee工程的核心檔案了。

1、首先完成剛才順手建立的test.mapper.User.xml。該檔案在《【Mybatis】Helloworld》(點選開啟連結)詳細說過了。主要是寫關於該User表的主要操作和test.dao下的Java方法對應關係。這裡分別有按照username查使用者、增加一個使用者、修改使用者名稱對應密碼的三個方法,也剛好展示Mybatis的增刪改查了。

<?xml version="1.0" encoding="UTF-8" ?>   
<!DOCTYPE mapper PUBLIC    
    "-//mybatis.org//DTD Mapper 3.0//EN"   
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test.dao.UserDao">
	<select id="findUsersByUsername" resultType="test.entity.User">
		select * from user
		where username=#{username}
	</select>
	<!--執行增加操作的SQL語句。id和parameterType分別與IUserOperation介面中的addUser方法的名字和引數型別一致。 
		useGeneratedKeys設定為"true"表明要MyBatis獲取由資料庫自動生成的主鍵; keyProperty="id"指定把獲取到的主鍵值注入到User的id屬性 -->
	<insert id="addUser" parameterType="test.entity.User"
		useGeneratedKeys="true" keyProperty="id">
		insert into
		user(username,password) values(#{username},#{password})
	</insert>
	<update id="modifyPasswordByUsername" parameterType="test.entity.User">
		update user set password=#{password} where username=#{username}
	</update>
</mapper> 

2、然後馬上來完成test.mapper.User.xml對應的test.dao.UserDao.java,具體如下所示,其實也沒什麼好說,就是一大堆方法的羅列,畢竟dao只是一個數據庫介面而已。這裡唯一需要大家注意的是,在SSM整合的過程中,我們需要對Dao層,標上@Repository的註解,讓Spring能識別這是Dao層。
package test.dao;

import org.springframework.stereotype.Repository;

import test.entity.User;

@Repository
public interface UserDao {
	public User findUsersByUsername(String username);

	public int addUser(User user);

	public int modifyPasswordByUsername(User user);
}

同時也順手完成剛才在test.mapper.User.xml提到的增刪改查的使用和返回型別,實體類test.entity.User.java。這樣的資料庫~Java實體,典型的private+getter+setter結構,相信大家早就見慣不怪了。
package test.entity;

public class User {
	
	private Integer id;
	private String username;
	private String password;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}

4、然後是Service層,也就是事務層,test.services.UserServices.java,這裡主要為Action層提供一系列封裝的方法,拿Action提供的資料操作資料庫,並且處理完返回資料給Action來應對jsp和java的互動,這往往是網頁工程的核心。

這裡一樣要嚴格註解一個@Service表示這是個事務層,不然Spring是直接識別不到報錯的。

package test.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import test.dao.UserDao;
import test.entity.User;

@Service
public class UserServices {
	
	@Autowired
	private UserDao userDao;//自動注入的存在,無需getter和setter了

	/*各個業務*/
	
	//判斷使用者是否存在
	public boolean isUserExist(String username) {
		if (userDao.findUsersByUsername(username) == null) {
			return false;
		} else {
			return true;
		}
	}

	//根據提供的使用者名稱拿密碼
	public String getPasswordByUsername(String username) {
		return userDao.findUsersByUsername(username).getPassword();
	}

	//新增一個使用者
	public void addUser(String username, String password) {
		User user = new User();
		user.setUsername(username);
		user.setPassword(password);
		userDao.addUser(user);
	}
  
	//修改某一使用者的密碼
	public void modifyPasswordByUsername(String username, String newpassword) {
		User user = userDao.findUsersByUsername(username);
		user.setUsername(username);
		user.setPassword(newpassword);
		userDao.modifyPasswordByUsername(user);
	}
	
}

另外,大家也可以從這個檔案看到Mybatis比Hibernate優秀的原因,Mybatis處理資料庫根本就沒有什麼commit不commit的提交事務才能修改資料庫事情!他就是一個簡單的SQL過程,上面的呼叫的dao方法,你完全可以理解成,這其實就是mapper一條對資料庫操作的sql語句,執行即更改。

5、之後是test.actions.WebAction.java,這裡也就是網頁的Action層了,這個檔案也在《【SpringMVC】Helloworld》(點選開啟連結)中詳細表述過了。

這裡在SSM同樣要明確地加上@Controller註解表示這是個Action層。

這裡也同時展示了SpringMVC中Java是如何拿前臺的資料,和返回資料到前臺的。拿前臺的資料主要是靠@RequestParam("前臺表單的name")+後臺Java的變數名了這個註解,當然還有拿其它資料的方式,不過這個是拿Post方法提交的表單資料最常用了,當然在get提供也可以照樣拿,其餘幾種拿前臺資料的方式比較少用,大家有興趣可以某度一下。@RequestMapping註解指明servlet的url和get/post的使用方式。

而返回資料到前臺,主要壓在model裡面,model可以放任何型別的東西,也就是objects。model可以用jsp3.0簡單的表示式${}列印,要是裡面放的是個list可以配合c標籤來列印。

至於各個方法如何處理使用者登入、註冊、修改密碼的細節,相信大家配合上面的test.services.UserServices.java一下就看得懂了,一點都不難,非常簡單的邏輯判斷。

package test.actions;

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.RequestParam;

import test.services.UserServices;

@Controller
public class WebAction {
	@Autowired
	private UserServices userServices;//自動注入的存在,getter和setter見鬼去吧!

	//跳轉到本工程主頁的action
	@RequestMapping(value = "/index")
	public String index() {
		return "index";
	}

	//關於使用者登入的表單提交
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(@RequestParam("username") String username,
			@RequestParam("password") String password, ModelMap model) {
		if (!userServices.isUserExist(username)) {
			model.addAttribute("msg", "使用者名稱不存在!");
		} else {
			if (password.equals(userServices.getPasswordByUsername(username))) {
				model.addAttribute("msg", "登入成功!");
			} else {
				model.addAttribute("msg", "密碼錯誤!");
			}
		}
		return "index";
	}

	//關於使用者註冊的表單提交
	@RequestMapping(value = "/register", method = RequestMethod.POST)
	public String register(@RequestParam("username") String username,
			@RequestParam("password") String password, ModelMap model) {
		if (userServices.isUserExist(username)) {
			model.addAttribute("msg", "使用者名稱已存在!");
		} else {
			userServices.addUser(username, password);
			model.addAttribute("msg", "註冊成功!");
		}
		return "index";
	}

	//關於修改密碼的表單提交
	@RequestMapping(value = "/modifyPassword", method = RequestMethod.POST)
	public String modifyPassword(@RequestParam("username") String username,
			@RequestParam("password") String password,
			@RequestParam("newpassword") String newpassword, ModelMap model) {
		if (!userServices.isUserExist(username)) {
			model.addAttribute("msg", "使用者名稱不存在!");
		} else {
			if (password.equals(userServices.getPasswordByUsername(username))) {
				userServices.modifyPasswordByUsername(username, newpassword);
				model.addAttribute("msg", "修改密碼成功!");
			} else {
				model.addAttribute("msg", "密碼錯誤!");
			}
		}
		return "index";
	}
	
}

6、最後完成view\index.jsp這一頁就大功告成了,views層也就是前端,非常簡單的東西,不多贅述了。本文為了只是用jsp3.0的表示式簡單列印了的string變數${msg},那些什麼列印使用者表就不做。要是model裡面放的是個list,可以參考《【Servlet】利用Servlet3.0標準與JSTL表示式實現檔案上傳系統,支援圖片上傳後顯示》(點選開啟連結)利用jstl表示式的c標籤,<c:foreach>列印了,這裡為了不雜糅jstl的技術,就不展示怎麼列印使用者表了。
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>主頁</title>
</head>
<body>
	<p style="color:red">${msg}</p><hr>
	使用者登入<br>
	<form action="login" method="post">
		使用者名稱:<input type="text" name="username" /><br>
		密碼:<input type="password" name="password" /><br>
		<input type="submit" value="提交"><br>
	</form><hr>
	使用者註冊<br>
	<form action="register" method="post">
		使用者名稱:<input type="text" name="username" /><br>
		密碼:<input type="password" name="password" /><br>
		<input type="submit" value="提交"><br>
	</form><hr>
	修改密碼<br>
	<form action="modifyPassword" method="post">
		使用者名稱:<input type="text" name="username" /><br>
		密碼:<input type="password" name="password" /><br>
		新密碼:<input type="password" name="newpassword" /><br>
		<input type="submit" value="提交"><br>
	</form><hr>		
</body>
</html>

最後,本文完成的例子可以在:http://download.csdn.net/download/yongh701/10124309,要是你的csdn下載分不多,或者我一樣很反感csdn的最新的必須要下載分才能下載的下載機制,也可以到https://github.com/yongh701/SSM下載。

大家看到這樣一套下來,Spring+SpringMVC+Mybatis比Struts2+Hibernate3+Spring3更接地氣,沒有什麼s標籤,沒有什麼又要多開一個xml檔案配action,也沒有hibernate那套什麼hql,完完全全就是你最常用的html語言和sql查詢。所以SSM逐漸流行起來了,其實在2014年甚至更早的時候,大家都已經對Struts2、Hibernate3頗有微詞,而隨著Spring的普及,中文資料漸漸增多,它已經不再單純是一個java~xml互動工具。簡單的註解方法,避免以前大量的xml檔案編寫,SpringMVC的高安全性,更加讓SSM成為業內的新寵!