功能介紹html
登陸頁面提供一個用戶名/密碼輸入表單,用戶填寫並提交表單後,服務端檢查是否有匹配的用戶名/密碼。若沒有,則返回到登陸頁面,並給出提示。若匹配,則記錄用戶的登陸日誌,更新用戶的最近登陸時間和IP,並給用戶增長5個積分,而後重定向到歡迎頁面。java
分析mysql
①首先由兩個實體對象類User、Log.實體對象類通常都有對應的數據表。web
②在持久層有兩個DAO類,UserDAO和LogDAO。UserDAO負責查詢用戶名/密碼是否存在,並更新用戶信息。LogDAO用來記錄登陸日誌。spring
在業務層有一個UserService服務類、sql
在視圖層有一個LoginController類,和兩個jsp頁面login.jsp和main.jsp。數據庫
用一個時序圖來描述登陸模塊的總體交互過程apache
環境準備app
①建立數據庫表框架
CREATE DATABASE sampleDB DEFAULT CHARACTOR SET UTF8;
USER sampleDB;
CREATE TABLE t_user (user_id int auto_increment primay kay,
user_name varchar(30),
credits int,
password varchar(30),
last_visit datetime,
last_ip varchar(30))ENGINE=InnoDB;
CREATE TABLE t_log (log_id int auto_increment primay kay,
user_id int,
ip varchar(30),
login_datetime datetime)ENGINE=InnoDB;
③創建工程。加入jar包spring.jar,commons-dbcp.jar,commons-logging.jar,jstl.jar.standard.jar,log4j-1.2.14.jar,mysql.jar,commons-pool.jar,junit,jar
⑤創建package
dao及其子包impl、domain、service、web、test
持久層開發
①創建實體對象
實體對象也稱領域對象,實體對象是數據表操做以面向對象的方式進行。持久層的主要工做就是從數據表中加載數據並實例化實體對象,或將實體對象持久化到數據表中。
public class User { private int userId; private String userName; private String password; private int credits; private String lastIp; private Date lastVisit; //省略getter/setter方法 } public class Log { private int logId; private int userId; private String ip; private Date loginDate; //省略getter/setter方法 }
②開發DAO及其實現類
public interface UserDAO { int getMatchCount(String userName, String password); User findUserByUsername(String username); void updateLoginInfo(User user); } public interface LogDAO { void insertLoginInfo(Log log); }
開發DAO的實現類
public class UserDAOImpl implements UserDAO { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate plate){ jdbcTemplate = plate; } public int getMatchCount(String userName, String password){ String sql = "SELECT count(*) FROM t_user WHERE user_name=? AND password=?"; return jdbcTemplate.queryForInt(sql, new Object[]{userName, password}); } public User findUserByUsername(String userName) { String sql = "SELECT user_id, user_name, credits FROM t_user WHERE user_name=?"; final User user = new User(); jdbcTemplate.query(sql, new Object[]{userName}, new RowCallbackHandler(){ public void processRow(ResultSet rs) throws SQLExeception{ user.setUserId(rs.get("user_id")); user.setUserName(userName); user.setCredits(rs.get("credits")); } }); return user; } public void updateLoginInfo(User user){ String sql = "UPDATE t_user SET last_visit=?,last_ip=?,credits=? WHERE user_id=?"; jdbcTemplate.update(sql, new Object[]{user.getLastVisit(), user.getLastIp(), user.getCredits(), user.getUserId()}); } } public class LogDAOImpl implements LogDAO { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate plate){ jdbcTemplate = plate; } public void insertLoginInfo(Log log){ String sql = "INSERT INTO t_log (user_id, ip, login_datetime) VALUES (?,?,?)"; jdbcTemplate.update(sql, new Object[]{log.getUserId(), log.getIp(), log.getLoginDate()}); } }
在Spring中裝配DAO
建立一個名爲myProject-dao.xml的spring配置文件。
JdbcTemplate自己須要一個DataSource,這樣他就能夠根據須要從數據庫鏈接池中獲取鏈接,因此必須先配置一個DataSource,而後定義一個JdbcTemplate Bean,而後再裝配好兩個DAObean
myProject-dao.xml <beans> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/sampleDB"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDAO" class="dao.UserDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <bean id="logDAO" class="dao.LogDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> </beans>
業務層開發
①開發業務層代碼
public interface UserService { boolean hasMatchUser(String userName, String password); User findUserByUserName(String userName); void loginSuccess(User user); } public classUserServiceImpl implements UserService { private UserDAO userDAO; private LogDAO logDAO; public void setUserDAO(UserDAO dao){ userDAO = dao; } public void setLogDAO(LogDAO dao){ logDAO = dao; } public boolean hasMatchUser(String userName, String password) { int matchCount = userDAO.getMatchCount(userName, password); return matchCount > 0; } User findUserByUserName(String userName) { return userDAO.findUserByUserName(userName); } void loginSuccess(User user) { user.setCredits(user.getCredits() + 5); Log log = new Log(); log.setUserId(user.getUserId()); log.setIp(user.getLastIp()); log.setLoginDate(user.getLastVisit()); userDAO.updateLoginInfo(user); logDAO.insertLoginLog(log); } }
②在spring中裝配Service。不只裝配兩個DAO,並且要配置聲明式事務。
聲明式事務配置:事務管理器(dataSource),target(要代理的對象),代理類(事務管理器,要代理的對象,策略)
myProject-service.xml <beans> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userServiceTarget" class="service.UserServiceImpl"> <property name="userDAO" ref="userDAO"/> <property name="logDAO" ref="logDAO"/> </bean> <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager"/> <property name="target" ref="userServiceTarget"/> <property name="transactionAttributes"> <props> <prop key="findUserByUserName"> PROPAGATION_REQUIRED,readOnly </prop> <prop key="hasMatchUser"> PROPAGATION_REQUIRED,readOnly </prop> <prop key="loginSuccess"> PROPAGATION_REQUIRED </prop> </props> </property> </bean> </beans>
視圖層開發
Struts2是最流行的視圖層框架。但我要先用SpringMVC來開發。
①配置Spring,使Web容器啓動時可以自動啓動Spring容器
在web.xml中配置 <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:myProject-dao.xml,classpath:myProject-service.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
②配置SpringMVC
在web.xml中配置 <servlet> <servlet-name>myProject</servlet> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>myProject</servlet> <url-pattern>*.html</url-pattern> </servlet-mapping>
SpringMVC一樣也有一個配置文件,默認爲:servlet名字-servlet.xml。並且這個文件必須放置在WEB-INF目錄下,並且這個文件無需在web.xml中說明,SpringMVC會自動將這個文件與其它的Spring的配置文件相拼裝。
請求被SpringMVC截獲後,首先根據請求的URL找到目標的處理控制器,並將請求參數封裝「命令」對象一塊兒傳給控制器處理,控制器調用Spring容器中的業務Bean完成業務處理工做並返回結果視圖。
處理登陸請求
①定義一個Command對象,來封裝表單的請求參數
public class LoginCommand { private String userName; private String password; //省略setter/getter方法
①控制器類LoginController,負責處理登陸請求,完成登陸業務,並根據登陸成功與否轉向歡迎頁面或失敗頁面
public class LoginController extends AbstractCommandController { private UserService userService; public LoginController(){ setCommandClass(LoginCommand.class); // } public void setUserService(UserService service){ userService = service; } protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException) throws Exception { LoginCommand loginCommand = (LoginCommand)command; boolean isValidUser = userService.hasMatchUser(loginCommand.getUserName(), loginCommand.getPassword()); if(!isValidUser){ return New ModelAndView("login", "error", "用戶名或密碼錯誤。"); }else { User user = userService.getUserByUserName(loginCommand.getUserName()); user.setLastIp(request.getLocalAddr()); user.setLastVisit(new Date()); userService.loginSuccess(user); request.getSession().setAttribute("user", user); return new ModelAndView("main"); } } }
②在SpringMVC的配置文件中,聲明控制器
myProject-servlet.xml <beans> <bean id="loginController" class="web.LoginController"> <property name="userService" ref="userService"/> </bean> ... </beans>
③如何經過URL來調用這個Controller呢?在web.xml中配置的因此.html的URL都截獲,它須要根據URL和控制器的映射才能進一步將截獲的請求轉發給某一特定的控制器處理。這個URL-控制器映射的工做能夠經過SpringMVC的SimpleUrlHandlerMapping來完成。
在myProject-servlet.xml中配置 <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/loginController.html">loginController</prop> </props> </property> </bean>
④ModelAndView的解析配置
ModelAndView的第一個參數表明視圖的邏輯名,第二個和第三個分別爲數據模型名稱和數據模型對像,將放置到request的屬性中。SpringMVC經過一個Bean將邏輯視圖名映射爲具體的視圖頁面。
在myProject-servlet.xml中配置 <bean id="viewResolver" class="org.springframework.web.servlet.view.InteralResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean>
JSP視圖頁面
login.jsp <body> <c:if test="${!empty error}"> <font color="red"><c:out value="${error}"/></font> </c:if> <form action="<c:url value="/loginController.html"/>" method="post"> 用戶名:<input type="text" name="userName"/><br> 密碼:<input type="password" name="password"/><br> <input type="submit" value="登陸"/> <input type="reset" value="重置"/> </form> </body> main.jsp <body> S{user.userName},歡迎到來,您的積分爲${user.credits}。 </body>
login.jsp位於WEB-INF下,沒法直接訪問,必須經過一個控制器來轉發。這個轉發控制器能夠繼承AbstractController。
public class LoginPage extends AbstractController { public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView("login"); } }
而後在URL解析器中加上一項映射
在myProject-servlet.xml中配置 <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/loginController.html">loginController</prop> <prop key="/index.html">loginPage</prop> </props> </property> </bean>
輸入URL http://localhost:8080/myProject/index.html便可看到網頁