首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring MVC 實戰項目:SpringTest 用戶認證系統完整架構與代碼實現

     編輯:Java 綜合教學

Spring MVC 實戰項目:SpringTest 用戶認證系統完整架構與代碼實現

本文記錄一個基於 Spring 3.1 + JdbcTemplate + MySQL 的經典 MVC 實戰項目 SpringTest,實現用戶註冊、登錄、登出功能。涵蓋專案搭建、配置文件、分層代碼、視圖頁面與運行驗證,適合 Spring 初學者理解請求處理全流程。

一、技術棧與環境

組件版本/選型
構建工具MyEclipse 10 (無 Maven,手動管理 JAR)
核心框架Spring 3.1 Core + Spring MVC
數據訪問Spring JdbcTemplate
資料庫MySQL 5.7.13
Web 容器Tomcat 7.0 (32位)
JDK1.6.0_13 (32位)
視圖技術JSP + JSTL

二、系統架構圖

┌─────────────┐     ┌──────────────┐     ┌─────────────┐     ┌──────────────┐
│   Browser   │────▶│DispatcherServlet│────▶│ Controller  │────▶│   Service/DAO │
│  (JSP View) │◀────│  (Front Ctrl)  │◀────│ (Action/Form)│◀────│  (JdbcTemplate)│
└─────────────┘     └──────────────┘     └─────────────┘     └──────────────┘
                           │
                    ┌──────┴──────┐
                    │  ViewResolver │
                    │ (InternalResource)│
                    └─────────────┘

三、核心配置文件

1. web.xml - 前端控制器與編碼過濾器

<web-app version="3.0" xmlns="https://java.sun.com/xml/ns/javaee" ...>
    <!-- 編碼過濾器 -->
    <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>*.do</url-pattern></filter-mapping>

    <!-- Spring MVC 前端控制器 -->
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping><servlet-name>spring</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping>

    <welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
</web-app>

2. spring-servlet.xml - 核心業務配置 (數據源、事務、DAO、Action、視圖解析、URL 映射)

<beans xmlns="https://www.springframework.org/schema/beans" ...>
    <!-- 數據源 (DBCP 連接池) -->
    <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/demo_test"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!-- 事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- DAO 定義 -->
    <bean id="userDAO" class="com.liu.spring.dao.UserDAO">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 事務代理 (舊版 Spring AOP 方式) -->
    <bean id="UserDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="target" ref="userDAO"/>
        <property name="transactionAttributes">
            <props>
                <prop key="insert*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>
    </bean>

    <!-- 視圖解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- URL 映射 (SimpleUrlHandlerMapping) -->
    <bean id="loginMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props><prop key="/login.do">loginAction</prop></props>
        </property>
    </bean>
    <bean id="logoutMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings"><props><prop key="/logout.do">logoutAction</prop></props></property>
    </bean>
    <bean id="registerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings"><props><prop key="/register.do">registerAction</prop></props></property>
    </bean>

    <!-- Action 定義 (繼承 SimpleFormController) -->
    <bean id="loginAction" class="com.liu.spring.actions.LoginAction">
        <property name="commandClass" value="com.liu.spring.forms.LoginForm"/>
        <property name="userDAO" ref="userDAO"/>
        <property name="formView" value="login"/>
        <property name="successView" value="welcome"/>
    </bean>
    <bean id="logoutAction" class="com.liu.spring.actions.LogoutAction">
        <property name="commandClass" value="com.liu.spring.forms.LoginForm"/>
        <property name="successView" value="login"/>
    </bean>
    <bean id="registerAction" class="com.liu.spring.actions.RegisterAction">
        <property name="commandClass" value="com.liu.spring.forms.RegisterForm"/>
        <property name="userDAO" ref="userDAO"/>
        <property name="formView" value="register"/>
        <property name="successView" value="login"/>
    </bean>
</beans>

四、分層代碼實現

1. 表單對象 (Command/Form)

// LoginForm.java
public class LoginForm {
    private String username;
    private String password;
    // getter/setter 省略
}

// RegisterForm.java
public class RegisterForm {
    private String username;
    private String password1;
    private String password2;
    private String email;
    // getter/setter 省略
}

2. 持久層實體與 DAO (JdbcTemplate)

// User.java (POJO)
public class User {
    private String id;
    private String username;
    private String password;
    private String email;
    // getter/setter 省略
}

// UserDAO.java
public class UserDAO {
    private DataSource dataSource;
    public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }

    public boolean isValid(String username, String password) {
        JdbcTemplate jt = new JdbcTemplate(dataSource);
        List list = jt.query("SELECT * FROM userInfo WHERE username=? AND password=?", 
            new Object[]{username, password}, new RowMapper() {
                public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                    User u = new User();
                    u.setId(rs.getString("ID"));
                    u.setUsername(rs.getString("username"));
                    u.setPassword(rs.getString("password"));
                    u.setEmail(rs.getString("email"));
                    return u;
                }
            });
        return !list.isEmpty();
    }

    public boolean isExist(String username) {
        JdbcTemplate jt = new JdbcTemplate(dataSource);
        Integer count = jt.queryForObject("SELECT COUNT(*) FROM userInfo WHERE username=?", 
            new Object[]{username}, Integer.class);
        return count > 0;
    }

    public void insertUser(User user) {
        JdbcTemplate jt = new JdbcTemplate(dataSource);
        jt.update("INSERT INTO userInfo(username,password,email) VALUES(?,?,?)",
            user.getUsername(), user.getPassword(), user.getEmail());
    }
}

3. 控制層 Action (繼承 SimpleFormController)

// LoginAction.java
public class LoginAction extends SimpleFormController {
    private UserDAO userDAO;
    public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; }

    @Override
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
                                    Object command, BindException errors) throws Exception {
        LoginForm form = (LoginForm) command;
        if (userDAO.isValid(form.getUsername(), form.getPassword())) {
            request.getSession().setAttribute("username", form.getUsername());
            return new ModelAndView(getSuccessView());  // welcome.jsp
        } else {
            errors.getModel().put("loginForm", form);
            return new ModelAndView(getFormView(), errors.getModel());  // login.jsp
        }
    }
}

// RegisterAction.java
public class RegisterAction extends SimpleFormController {
    private UserDAO userDAO;
    public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; }

    @Override
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
                                    Object command, BindException errors) throws Exception {
        RegisterForm form = (RegisterForm) command;
        String method = request.getParameter("method");
        if ("register".equals(method)) {
            if (!userDAO.isExist(form.getUsername())) {
                User user = new User();
                user.setUsername(form.getUsername());
                user.setPassword(form.getPassword1());
                user.setEmail(form.getEmail());
                userDAO.insertUser(user);
                response.sendRedirect("login.do");  // 註冊成功重定向登錄頁
                return null;
            } else {
                errors.getModel().put(getFormSessionAttributeName(), form);
                return new ModelAndView(getFormView(), errors.getModel());  // 回註冊頁
            }
        }
        return new ModelAndView(getFormView());  // 初始顯示註冊頁
    }
}

// LogoutAction.java
public class LogoutAction extends SimpleFormController {
    @Override
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
                                    Object command, BindException errors) throws Exception {
        request.getSession().invalidate();  // 銷毀 Session
        response.sendRedirect("login.do");
        return null;
    }
}

4. 常量類

public class Constants {
    public final static String USERNAME_KEY = "username";
}

五、視圖層 JSP 頁面

1. login.jsp - 登錄頁

<%@ page language="java" pageEncoding="UTF-8"%>
<% String path = request.getContextPath(); 
   String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>
<html><head><base href="<%=basePath%>"><title>用戶登錄</title></head><body>
<form name="form1" action="login.do" method="post">
<table width="200" border="1">
<tr><td colspan="2">登錄窗口</td></tr>
<tr><td>用戶名</td><td><input type="text" name="username" size="10"></td></tr>
<tr><td>密碼</td><td><input type="password" name="password" size="10"></td></tr>
<tr><td colspan="2">
    <input type="submit" name="submit" value="登錄"> 
    <a href="register.do?method=init">註冊新用戶</a>
</td></tr>
</table></form></body></html>

2. register.jsp - 註冊頁

<form name="form1" action="register.do?method=register" method="post">
<table width="200" border="1">
<tr><td colspan="2">註冊窗口</td></tr>
<tr><td>用戶名</td><td><input type="text" name="username" size="10"></td></tr>
<tr><td>密碼</td><td><input type="password" name="password1" size="10"></td></tr>
<tr><td>確認密碼</td><td><input type="password" name="password2" size="10"></td></tr>
<tr><td>Email</td><td><input type="text" name="email" size="10"></td></tr>
<tr><td colspan="2">
    <input type="submit" value="註冊"> <a href="login.do">返回</a>
</td></tr>
</table></form>

3. welcome.jsp - 登錄成功頁

<form name="form1" action="logout.do" method="post">
<table width="200" border="1">
<tr><td colspan="2">登錄成功</td></tr>
<tr><td>歡迎你,</td><td><%=session.getAttribute("username")%></td></tr>
<tr><td colspan="2"><input type="submit" name="submit" value="退出"></td></tr>
</table></form>

六、資料庫表結構

CREATE DATABASE demo_test DEFAULT CHARACTER SET utf8;
USE demo_test;
CREATE TABLE userInfo (
    ID INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(50) NOT NULL,
    email VARCHAR(100)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

七、運行驗證流程

  1. 啟動 MySQL,執行建表 SQL
  2. 部署項目至 Tomcat 7
  3. 訪問 https://localhost:8080/SpringTest/login.jsp
  4. 點擊「註冊新用戶」填寫信息提交
  5. 返回登錄頁,使用剛註冊賬號登錄
  6. 顯示歡迎頁,點擊「退出」返回登錄頁

八、項目結構總覽

SpringTest/
├── src/
│   ├── com.liu.spring.actions/   (LoginAction, RegisterAction, LogoutAction)
│   ├── com.liu.spring.dao/       (UserDAO, User)
│   ├── com.liu.spring.forms/     (LoginForm, RegisterForm)
│   └── com.liu.spring.util/      (Constants)
├── WebRoot/
│   ├── WEB-INF/
│   │   ├── web.xml
│   │   ├── spring-servlet.xml
│   │   └── lib/ (spring.jar, mysql-connector.jar, commons-dbcp.jar, ...)
│   ├── login.jsp
│   ├── register.jsp
│   └── welcome.jsp
└── 數據庫腳本.sql

九、現代化改造建議 (Spring Boot 3.x)

原技術現代替代改造要點
XML 配置Java Config / YAML@Configuration、@Bean、application.yml
SimpleFormController@Controller + @RequestMappingPOJO 入參、@Valid 驗證、統一異常處理
JdbcTemplateSpring Data JPA / MyBatisRepository 介面、實體映射、分頁查詢
DBCPHikariCPSpring Boot 2+ 默認連接池
JSPThymeleaf / 前後端分離 (Vue/React)模板引擎或 REST API + 前端框架
手動 JAR 管理Maven / Gradle依賴傳遞、版本衝突解決、構建自動化
明文密碼BCrypt 加密BCryptPasswordEncoder、Spring Security

學習價值:雖然技術棧較老,但 SpringTest 完整展示了 Spring MVC 請求處理核心流程:DispatcherServlet → HandlerMapping → Controller → Service/DAO → ViewResolver → JSP。理解這套流程,對學習現代 Spring Boot、Spring Cloud 微服務有極大幫助。

源碼參考:GitHub - SpringTest

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved