本文通過一個完整的**用戶註冊/登入/註銷**案例,展示經典 JavaEE 三層架構落地:Servlet (控制層) → Service (業務層) → DAO (數據層) → Domain (實體),並採用 **DOM4J 操作 XML 模擬數據庫**、**工廠模式解耦創建**、**XPath 查詢**、**BeanUtils 自動封裝**等實用技術。
com.tsh ├─ web // Servlet 控制器 ├─ service // 業務邏輯接口及實現 ├─ dao // 數據訪問接口及實現 ├─ domain // 實體類 ├─ util // 工具類 ├─ factory // 工廠類 (解耦創建) ├─ exception // 自定義異常 └─ test // 單元測試
dom4j:XML 解析與寫入jstl:JSP 標簽庫commons-beanutils:表單數據自動封裝到 Beanjunit:單元測試package com.tsh.domain;
import java.io.Serializable;
public class User implements Serializable {
private String username;
private String password;
private String password_confirm; // 前端確認密碼用
// Getter/Setter 省略
}
package com.tsh.dao;
import com.tsh.domain.User;
import com.tsh.util.XmlDaoUtil;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.util.List;
public class XmlUserDao {
// 根據用戶名查找
public User findUserByUsername(String username) {
Document dom = XmlDaoUtil.getDom();
Element root = dom.getRootElement();
// XPath 查詢://user[@username='xxx']
List list = root.selectNodes("//user[@username='" + username + "']");
if (list.size() > 0) {
Element userElement = list.get(0);
User user = new User();
user.setUsername(userElement.attributeValue("username"));
user.setPassword(userElement.attributeValue("password"));
user.setPassword_confirm(userElement.attributeValue("password")); // 簡化
return user;
}
return null;
}
// 添加用戶
public void addUser(User user) {
Document dom = XmlDaoUtil.getDom();
Element root = dom.getRootElement();
Element userElement = DocumentHelper.createElement("user");
userElement.setAttributeValue("username", user.getUsername());
userElement.setAttributeValue("password", user.getPassword());
root.add(userElement);
XmlDaoUtil.writeXml(dom); // 回寫文件
}
}
package com.tsh.util;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import java.net.URL;
public class XmlDaoUtil {
private static URL path = XmlDaoUtil.class.getClassLoader().getResource("user.xml");
private static Document dom;
static {
SAXReader reader = new SAXReader();
try {
dom = reader.read(path);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Document getDom() {
return dom;
}
public static void writeXml(Document dom) {
// 實現寫回文件邏輯 (省略)
}
}
user.xml (放置於 src 根目錄,編譯到 classes)
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user username="admin" password="admin"/>
</users>
config.properties
dao=com.tsh.dao.XmlUserDao service=com.tsh.service.impl.UserServiceImpl
// Service 接口
public interface UserService {
void register(User user) throws UserExistException;
User login(String username, String password) throws UserNotFoundException, PasswordErrorException;
}
// Service 實現
public class UserServiceImpl implements UserService {
private UserDao userDao = (UserDao) BeanFactory.getBean("dao");
public void register(User user) throws UserExistException {
if (userDao.findUserByUsername(user.getUsername()) != null) {
throw new UserExistException("用戶名已存在");
}
userDao.addUser(user);
}
// login 實現省略
}
// 簡易工廠 (反射 + 配置文件)
public class BeanFactory {
private static Properties props = new Properties();
static {
try {
props.load(BeanFactory.class.getClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e) { e.printStackTrace(); }
}
public static Object getBean(String key) {
String className = props.getProperty(key);
try {
return Class.forName(className).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
// 1. BeanUtils 自動封裝表單數據到 User
User user = new User();
try {
BeanUtils.populate(user, req.getParameterMap());
} catch (Exception e) { throw new RuntimeException(e); }
// 2. 調用 Service
UserService service = (UserService) BeanFactory.getBean("service");
try {
service.register(user);
resp.sendRedirect("login.jsp?msg=註冊成功");
} catch (UserExistException e) {
req.setAttribute("msg", e.getMessage());
req.getRequestDispatcher("register.jsp").forward(req, resp);
}
}
}
selectNodes("//user[@username='...']") 極其適合 XML 模擬數據庫查詢,無需學習 SQL。XmlDaoUtil 靜態塊加載一次,讀取極快;寫入時需同步考慮併發 (簡單項目可加鎖)。request.getParameterMap() → Bean 屬性 映射,自動類型轉換。這個微型專案雖簡單,卻包含了**分層架構、接口解耦、配置驅動、ORM 思想、異常體系**等企業級開發核心基因,是進階 JavaEE 的優秀起步樣板。