Spring 入門例項 簡易登入系統(精通Spring+4.x++企業應用開發實戰 學習筆記一)
論壇登入模組
在持久層有兩個DAO類,分別是UserDao和LoginLogDao,在業務層對應一個業務類UserService,在展現層擁有一個LoginController類和兩個JSP頁面,分別是登入頁面login.jsp和登入成功頁面main.jsp
DAO為資料訪問物件(Data Access Object DAO)設計模式,以便將低級別的資料訪問邏輯與高級別的業務邏輯分離。
下載jdk和maven,mysql並配置好環境變數
1.建立庫表
(1)登入資料庫
mysql -u root -p
設定密碼格式為
set password for 使用者名稱@localhost = password('新密碼');
(2)建立例項對應的資料庫
DROP DATABASE IF EXISTS sampledb;
CREATE DATABASE sampledb DEFAULT CHARACTER SET utf8;
USE sampledb;
預設字符集採用UTF-8
(3)建立例項所用的兩張表
建立使用者表
CREATE TABLE t_user(
user_id INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(30),
credits INT ,
password VARCHAR(32),
last_visit datetime,
last_ip VARCHAR(23)
)ENGINE=InnoDB;
建立用於使用者登入日誌表
CREATE TABLE t_login_log(
login_log_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
ip VARCHAR(23),
login_datetime datetime
)ENGINE=InnoDB;
InnoDB引擎支援事務
(4)初始化一條資料
INSERT INTO t_user (user_name,password) VALUES ('admin','123456');
COMMIT;
也可以直接執行指令碼檔案sampledb.sql
2.在IDEA中建立一個專案
其中的pom.xml配置從下載的原始碼中直接使用
類包以分層的方式進行組織
3.持久層
領域物件(Domain Object)也稱為實體類,它代表了業務的狀態,且貫穿表現層,業務層和持久層,並最終被持久化到資料庫中。
持久層的主要工作就是從資料庫中載入資料並例項化領域物件,或者將領域物件持久化到資料庫表中。
“持久層”,也就是在系統邏輯層面上,專著於實現資料持久化的一個相對獨立的領域(Domain),是把資料儲存到可掉電式儲存裝置中。持久層是負責向(或者從)一個或者多個數據儲存器中儲存(或者獲取)資料的一組類和元件。
這個層必須包括一個業務領域實體的模型(即使只是一個元資料模型)。
使用者領域物件
使用者資訊領域物件可以看成t_user表的物件映像,每個欄位對應一個物件屬性。
有3類資訊:userName/password,積分(credits)和最後一次登入的資訊(lastIp,lastVisit)
package com.smart.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable{
private int userId;
private String userName;
private String password;
private int credits;
private String lastIp;
private Date lastVisit;
//省略get/set方法
}
登入日誌領域物件
使用者每次成功登入後都會記錄一條登入日誌
3類資訊:使用者ID,登入IP和登入時間。(一般情況下還需退出時間)
package com.smart.domain;
import java.io.Serializable;
import java.util.Date;
public class LoginLog implements Serializable {
private int loginLogId;
private int userId;
private String ip;
private Date loginDate;
//省略get/set方法
}
UserDao
包括三個方法:
①getMatchCount():
根據使用者名稱和密碼獲取匹配的使用者數。等於1表示使用者名稱/密碼正確,0則錯誤(這是最簡單的使用者身份認證方法,實際中還需很多安全策略)
②findUserByUserName:
根據使用者名稱獲取User物件
③updateLoginInfo():
更新使用者積分,最後登入IP及最後登入時間
package com.smart.dao;
import com.smart.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;
import sun.security.krb5.internal.PAData;
import java.sql.ResultSet;
import java.sql.SQLException;
@Repository //通過Spring註解一個DAO
public class UserDao {
private JdbcTemplate jdbcTemplate; //資料庫相關操作
private final static String MATCH_COUNT_SQL = " SELECT count(*) FROM t_user " +
" WHERE user_name =? and password=? ";
private final static String UPDATE_LOGIN_INFO_SQL = " UPDATE t_user SET " +
" last_visit=?,last_ip=?,credits=? WHERE user_id =?";
@Autowired //自動注入JdbcTemplate的Bean,@Autowired是一種函式,可以對成員變數、方法和建構函式進行標註,來完成自動裝配的工作
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
//返回1表示表示使用者名稱/密碼正確,0則錯誤
public int getMatchCount(String userName, String password) {
//第一個引數是傳入的mysql語句,第二個是參入的引數,第三個引數指定需要返回什麼型別
return jdbcTemplate.queryForObject(MATCH_COUNT_SQL, new Object[]{userName, password}, Integer.class);
}
public User findUserByUserName(final String userName){
String sqlStr = " SELECT user_id,user_name,credits "
+ " FROM t_user WHERE user_name =? ";
final User user=new User();
jdbcTemplate.query(sqlStr, new Object[]{userName},
//匿名類方式實現的回撥函式,RowCallbackHandler只處理單行結果
new RowCallbackHandler() { //rs是查詢後返回的結果集
public void processRow(ResultSet rs) throws SQLException {
user.setUserId(rs.getInt("user_id"));
user.setUserName(userName);
user.setCredits(rs.getInt("credits"));
}
});
return user;
}
public void updateLoginInfo(User user) {
jdbcTemplate.update(UPDATE_LOGIN_INFO_SQL, new Object[] { user.getLastVisit(),
user.getLastIp(),user.getCredits(),user.getUserId()});
}
}
@Repository用於標註資料訪問元件,即DAO元件
@Autowired是一種函式,可以對成員變數、方法和建構函式進行標註,來完成自動裝配的工作
Spring JDBC通過一個模板類JdbcTemplate封裝了樣板式的程式碼,使用者通過模板類可以輕鬆地完成大部分資料訪問操作。
query(String sqlStr,Object[] args,RowCallbackHandler rch)有三個引數
①sqlStr:SQL語句,允許使用帶”?”的佔位符
②args:SQL語句中對應位置的引數陣列
③RowCallbackHandler :查詢結果的處理回撥介面,該介面有一個方法processRow(ResultSet rs),負責將查詢的結果從ResultSet裝載到類似於領域物件的物件例項中
在DAO中編寫SQL語句中,通常將SQL語句寫在靜態變數中,如果太長則採用多行字串的方式進行構造。在每行SQL語句的句尾和句前都加一個空格,就可以避免分行SQL組合後的錯誤。
LoginLogDao
package com.smart.dao;
import com.smart.domain.LoginLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository //通過Spring註解一個DAO
public class LoginLogDao {
private JdbcTemplate jdbcTemplate;
//儲存登入日誌SQL
private final static String INSERT_LOGIN_LOG_SQL=
"INSERT INTO t_login_log(user_id,ip,login_datetime) VALUES(?,?,?)";
public void insertLoginLog(LoginLog loginLog){
Object[] args={loginLog.getUserId(),loginLog.getIp(),loginLog.getLoginDate()};
jdbcTemplate.update(INSERT_LOGIN_LOG_SQL,args);
}
@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
}
在Spring中裝配DAO
樣板式的操作都被JdbcTemplate封裝起來了,JdbcTemplate本身需要一個DataSource,這樣它就可以根據需要從DataSource中獲取或返回連線。
UserDao和LoginLogDao都提供了一個帶@Autowired註解的JdbcTemplate變數,所以我們必須先宣告一個數據源,然後定義一個JdbcTemplate Bean,通過Spring容器上下文自動繫結機制進行Bean的注入。
在src\resources(Maven工程中,資原始檔統一放置在resources資料夾中)目錄下建立一個名為smart-context.xml的Spring配置檔案
<?xml version="1.0" encoding="UTF-8" ?>
<!-- ①引入Spring的多個Schema空間的格式定義檔案和引入aop及tx名稱空間鎖對應的Schema檔案 -->
<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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- ②掃描類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入 -->
<context:component-scan base-package="com.smart.dao"/>
<context:component-scan base-package="com.smart.service"/>
<!--③定義一個使用DBCP 配置資料來源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/sampledb"
p:username="root"
p:password="123456" />
<!-- ④配置Jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource" />
<!--⑤ 配置事務管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
<!-- ⑥通過AOP配置提供事務增強,讓service包下所有Bean的所有方法擁有事務 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod"
expression="(execution(* com.smart.service..*(..))) and (@annotation(org.springframework.transaction.annotation.Transactional))" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
</beans>
在②中,掃描類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入
這一步中使用Spring的 掃描指定類包中的所有類,這樣在類中定義的Spring註解(如Repository,@Autowired等)才能產生作用
在③配置資料來源
使用dbcp定義了一個數據源,驅動器類為com.mysql.jdbc.Driver,指定MySQL資料庫的服務埠(非預設3306時)
在④配置了JdbcTemplate Bean,將③處宣告的DataSource注入JdbcTemplate中,而這個JdbcTemplare將通過@Autowired自動注入LoginDao和UserDao的Bean中,可見Spring可以很好地將註解配置和XML配置統一起來。
業務層
在此例項中僅有一個業務類UserService,負責將持久層的UserDao和LoginlogDao組織起來,完成使用者/密碼認證,登入日誌記錄等操作。
有3個業務辦法:
①hasMatchUser
用於檢查使用者名稱/密碼的正確性
②findUserByUserName
以使用者名稱來條件載入User物件
③loginSuccess
在使用者登入成功後呼叫,更新使用者最後登入時間和IP資訊,同時記錄使用者登入日誌
package com.smart.service;
import com.smart.dao.LoginLogDao;
import com.smart.dao.UserDao;;
import com.smart.domain.LoginLog;
import com.smart.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service //將UserService標註為一個服務層的Bean
public class UserService {
private UserDao userDao;
private LoginLogDao loginLogDao;
@Autowired // 注入userDao的Bean
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
@Autowired //注入loginLogDao的Bean
public void setLoginLogDao(LoginLogDao loginLogDao){
this.loginLogDao=loginLogDao;
}
public boolean hasMatchUser(String userName,String paasword){
int matchCount=userDao.getMatchCount(userName,paasword);
return matchCount>0;
}
public User findUserByUserName(String userName){
return userDao.findUserByUserName(userName);
}
@Transactional //標註事務註解,讓該方法執行在事務環境中,否則該方法在事務中無法執行
public void loginSuccess(User user){
user.setCredits(5+user.getCredits());
LoginLog loginLog=new LoginLog();
loginLog.setUserId(user.getUserId());
loginLog.setIp(user.getLastIp());
loginLog.setLoginDate(user.getLastVisit());
userDao.updateLoginInfo(user);
loginLogDao.insertLoginLog(loginLog);
}
}
loginSuccess()方法將兩個Dao組織起來,共同完成一個事務性的資料操作。
loginSuccess()方法根據入參user物件構造出LoginLog物件並將user.credits遞增5,即每登入一次賺錢5個積分,然後呼叫userDao更新到t_user中,再呼叫loginLogDao向t_login_log表中新增一條記錄。
在Spring中裝配Service
在上面中smart-context.xml配置檔案中,可以發現
在①中,在beans宣告處新增aop和tx名稱空間定義檔案的說明,這樣,在配置檔案中就可以使用這兩個空間下的配置標籤了
在②中將service新增到上下文掃描路徑中,以便使service包中類的Spring註解生效
在⑤中,配置的事務管理器,負責宣告式事務的管理,需要應用dataSource Bean
在⑥通過AOP配置提供事務增強,讓service包下所有Bean的所有方法擁有事務
通過aop及tx名稱空間的語法,以AOP的方式為service包下所有類的所有標註@Transactional註解的方法都添加了事務增強,它們都將工作在事務環境中
單元測試
這裡使用的測試採用TestNG框架
在test目錄下,建立com.smart.service,並建立UserService對應的測試類UserServiceTest
package com.smart.service;
import java.util.Date;
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
import org.testng.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import com.smart.domain.User;
import static org.testng.Assert.*;
@ContextConfiguration("classpath*:/smart-context.xml") //啟動Spring容器,用於指定Spring的配置檔案
public class UserServiceTest extends AbstractTransactionalTestNGSpringContextTests {
@Autowired
private UserService userService;
@Test //標註測試方法
public void testHasMatchUser(){
boolean b1=userService.hasMatchUser("admin","123456");
boolean b2=userService.hasMatchUser("admin","1111");
assertTrue(b1);
assertTrue(!b2);
}
@Test
public void testFindUserByUserName()throws Exception{
for(int i=0;i<100;i++){
User user=userService.findUserByUserName("admin");
assertEquals(user.getUserName(),"admin");
}
}
@Test
public void testAddLoginLog(){
User user = userService.findUserByUserName("admin");
user.setUserId(1);
user.setUserName("admin");
user.setLastIp("192.168.12.7");
user.setLastVisit(new Date());
userService.loginSuccess(user);
}
}
UserServiceTest通過測試基類AbstractTransactionalTestNGSpringContextTests來啟動測試執行器。
@ContextConfiguration用於指定Spring的配置檔案
右鍵Run UserServiceTest可以看到3個業務方法已成功執行
展現層
配置Spring MVC框架
對web.xml(放在/WEB-INF目錄下)進行配置,以便Web容器啟動時能自動啟動Spring容器
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- ①從類路徑下載入Spring配置檔案,classpath關鍵字特指類路徑下載入-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:smart-context.xml</param-value>
</context-param>
<!-- ②負責啟動Spring容器的監聽器,將應用①處的context引數獲得Spring配置檔案的地址-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Spring MVC的主控Servlet-->
<servlet> <!-- ③-->
<servlet-name>smart</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<!--Spring MVC處理的URL-->
<servlet-mapping> <!-- ④-->
<servlet-name>smart</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
在①處通過Web容器引數指定Spring配置檔案的地址
在②處指定Spring所提供的ContextLoaderListener的Web容器監聽器,該監聽器在Web容器啟動時自動執行,它會根據contextConfigLocation Web容器引數獲取Spring配置檔案,並啟動Spring容器。
注意,需要將log4J.propertis日誌配置檔案放置在類路徑下,以便日誌引擎自動生效
log4j.rootLogger=INFO,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n
在③處聲明瞭一個Servlet,名為smart,則在/WEB-INF目錄下必須提供一個名為smart-servlet/xml的Spring MVC配置檔案,Spring MVC的Servlet會自動將smart-servlet.xml檔案和Spring的其他配置檔案(smart-dao.xml,smart-service.xml)進行拼裝。
在④處對這個Servlet的URL路徑對映進行定義,讓所有以.html為字尾的URL都能被smart Servlet截獲,進而轉由Spring MVC框架進行處理。
請求被Spring MVC截獲後,首先根據請求的URL查詢到目標的處理控制器,並將請求引數封裝“命令”物件一起傳給控制器處理;然後,控制器呼叫Spring容器中的業務Bean完成業務處理工作並返回結果檢視。
處理登入請求
POJO(Plain Ordinary Java Object,簡單的Java物件)控制器類
LoginController負責處理登入請求,完成登入業務,並根據登入成功與否轉向成功或失敗頁面
package com.smart.web;
import com.smart.domain.User;
import com.smart.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Controller //標註為一個Spring MVC的Controller
public class LoginController {
private UserService userService;
//②負責處理/index.html的請求
@RequestMapping(value="/index.html")
public String loginPage(){
return "login";
}
//③負責處理/loginCheck.html的請求
@RequestMapping(value = "/loginCheck.html")
public ModelAndView loginCheck(HttpServletRequest request, LoginCommand loginCommand){
boolean isValidUser=userService.hasMatchUser(loginCommand.getUserName(),loginCommand.getPassword());
if(!isValidUser){
return new ModelAndView("login","error","使用者名稱或密碼錯誤");
}else{
User user=userService.findUserByUserName(loginCommand.getUserName());
user.setLastIp(request.getLocalAddr());
user.setLastVisit(new Date());
userService.loginSuccess(user);
request.getSession().setAttribute("user",user);//將user放入Session域
return new ModelAndView("main");
}
}
@Autowired
public void setUserService(UserService userService){
this.userService=userService;
}
}
通過@Controller註解可以將任何一個POJO的類標註為Spring MVC的控制器處理HTTP請求。
通過@RequestMapping指定方法如何對映請求路徑
請求引數會根據引數名稱預設契約自動繫結到相應方法的入參中。如loginCheck(HttpServletRequest request, LoginCommand loginCommand)方法中,請求引數會按匹配繫結到loginCommand的入參中。
請求響應方法可以返回一個ModelAndView,或直接返回一個字串,Spring MVC會解析並轉向目標響應頁面。
LoginCommand是一個POJO,僅包含使用者/密碼兩個屬性
package com.smart.web;
public class LoginCommand {
private String userName;
private String password;
//get/set方法
}
Spring MVC配置檔案
編寫好LoginCommand後,需要在smart-servlet.xml(在/WEB-INF目錄下)宣告該控制器,掃描Web路徑,指定Spring MVC的檢視解析器
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- ①掃描web包,應用Spring的註解 -->
<context:component-scan base-package="com.smart.web"/>
<!-- ②配置檢視解析器,將ModelAndView及字串解析為具體的頁面 -->
<!-- 通過prefix指定在檢視名前所新增的字首,通過suffix指定在檢視名後新增的字尾
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
</beans>
在LoginController中的③處,控制器根據登入處理結果分別返回ModelAndView(“login”,”error”,”使用者名稱或密碼錯誤”)和ModelAndView(“main”)。
第一個引數代表檢視的邏輯名,第二為資料模型名稱,第三為資料模型物件,資料模型物件將以資料模型名稱為引數放入request的屬性中
Spring MVC為檢視名到具體檢視的對映提供了許多可選擇的方法,此使用InternalResourceViewResolver,它通過為檢視邏輯名新增字首,字尾的方式進行解析。
如檢視邏輯名為”login”,將解析為/WEB-INF/jsp/login.jsp
JSP檢視頁面
登入頁面為login.jsp和歡迎頁面為main.jsp
登入頁面login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>論壇登入</title>
</head>
<body>
<c:if test="${!empty error}">
<font color="red"><c:out value="${error}" /></font>
</c:if>
<form action="<c:url value="loginCheck.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>
</html>
login.jsp有兩個作用,即作為登入頁面,也作為登入失敗後的響應頁。
在<c:if test=”${!empty error}”>處使用JSTL標籤對登入錯誤返回的資訊進行處理。在JSTL標籤中引用了error變數,這個變數正是ModelAndView(“login”,”error”,”使用者名稱或密碼錯誤”)物件所宣告的error引數
在<form action=”<c:url value=”loginCheck.html”/>” method=”post”>中login.jsp的登入表單提交到/loginController.html,而loginController中@RequestMapping(value = “/loginCheck.html”)負責處理/loginCheck.html的請求。
JSTL標籤會在URL前自動加上應用部署根目錄。假設應用部署在網站的bbt目錄下,則<c:url>標籤將輸出/bbt/loginController.html
由於login.jsp放在WEB-INF/jsp目錄中,無法直接通過URL進行呼叫,所以由LoginController控制類中標註了 @RequestMapping(value=”/index.html”)的loginPage()進行轉發
歡迎頁面main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>論壇</title>
</head>
<body>
${user.userName},歡迎您進入論壇,您當前積分為${user.credits};<!-- ① -->
</body>
</html>
①處訪問Session域中的user物件,顯示使用者名稱和積分資訊
執行Web應用
基於Maven工程,執行Web應用有兩種方式:第一種方式是在IDE工具中配置Web應用伺服器,第二種方式是在pom.xml檔案中配置Web應用伺服器外掛
在pom.xml中
<build>
<plugins>
<!-- jetty外掛 -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.25</version>
<configuration>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>8000</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
<contextPath>/bbs</contextPath>
<scanIntervalSeconds>0</scanIntervalSeconds>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<parallel>methods</parallel>
<threadCount>10</threadCount>
</configuration>
</plugin>
</plugins>
</build>
Jetty外掛常用配置選項說明:
在Connenctors中配置Connector物件,包含Jetty的監聽埠。如果不配置聯結器,則預設監聽埠會被設定為8080.
contextPath可選,用於配置Web應用上下文。如果不配置此項,則預設上下文采用pom.xml中設定的<artfacId>名稱,本例將上下文設定為bbs
overridWebXml可選,是一個應用於Web應用的web.xml的備用web.xml檔案。這個檔案可以放在任何地方。使用者可以根據不同的環境(如測試,開發 等),利用它增加或修改一個web.xml配置。
scanIntervalSeconds 可選,在設定間隔內檢查Web應用是否有變化,有變則自動熱部署。預設為0,表示禁用熱部署,任意一個大於0的數字都表示啟用
systemPropertie可選,允許使用者在設定一個外掛的執行操作時配置系統屬性
點選
中的
在Plugins下會自動出現安裝的Jetty外掛。
雙擊jetty:run或jetty:run-exploded,將以執行模式啟動Jetty伺服器,也可以使用Debug執行。
下圖是論壇登入的首頁面
密碼或使用者名稱錯誤時
這裡輸入admin/123456(之前已先初始化),登入到歡迎頁面中,如圖
通過檢視MySQL,可以發現數據庫發生了變化