JavaWeb开发系列(七)表单开发

表单开发

Java Web 表单开发详解

一、表单开发核心组件

组件 作用 常用实现
HTML表单 前端数据收集界面 <form>, <input>, <select>
Servlet 接收并处理表单数据 HttpServlet, doPost(), doGet()
JSP页面 显示表单和处理结果 EL表达式, JSTL标签
JavaBean 封装表单数据 POJO类, 遵循JavaBean规范
验证框架 数据验证 Hibernate Validator, 自定义验证

二、表单数据流转流程

复制代码
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   HTML表单   │ →  │   Servlet    │ →  │   JavaBean   │ →  │   数据库     │
│   (JSP)     │ ←  │   (控制器)   │ ←  │   (模型)     │ ←  │   (持久层)   │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
      ↑                     ↑                     ↑
  用户输入              业务逻辑              数据封装

三、基础表单示例

1. HTML/JSP 表单页面

jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" %>
<form action="register" method="post">
    <table border="1">
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username" required></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" required></td>
        </tr>
        <tr>
            <td>邮箱:</td>
            <td><input type="email" name="email"></td>
        </tr>
        <tr>
            <td>性别:</td>
            <td>
                <input type="radio" name="gender" value="male">男
                <input type="radio" name="gender" value="female">女
            </td>
        </tr>
        <tr>
            <td>爱好:</td>
            <td>
                <input type="checkbox" name="hobbies" value="reading">阅读
                <input type="checkbox" name="hobbies" value="sports">运动
                <input type="checkbox" name="hobbies" value="music">音乐
            </td>
        </tr>
        <tr>
            <td>城市:</td>
            <td>
                <select name="city">
                    <option value="beijing">北京</option>
                    <option value="shanghai">上海</option>
                    <option value="guangzhou">广州</option>
                </select>
            </td>
        </tr>
        <tr>
            <td colspan="2" align="center">
                <input type="submit" value="注册">
                <input type="reset" value="重置">
            </td>
        </tr>
    </table>
</form>

2. JavaBean (POJO)

java 复制代码
public class User {
    private String username;
    private String password;
    private String email;
    private String gender;
    private String[] hobbies;
    private String city;
    
    // 构造方法、getter和setter
    public User() {}
    
    // 必须有无参构造方法
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    // 其他getter/setter...
}

3. Servlet 处理表单

java 复制代码
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        // 1. 设置编码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        // 2. 获取表单数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String gender = request.getParameter("gender");
        String[] hobbies = request.getParameterValues("hobbies"); // 多值参数
        String city = request.getParameter("city");
        
        // 3. 数据验证
        List<String> errors = new ArrayList<>();
        if (username == null || username.trim().isEmpty()) {
            errors.add("用户名不能为空");
        }
        if (password == null || password.length() < 6) {
            errors.add("密码长度至少6位");
        }
        
        // 4. 封装到JavaBean
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setEmail(email);
        user.setGender(gender);
        user.setHobbies(hobbies);
        user.setCity(city);
        
        // 5. 业务处理和数据存储
        
        // 6. 转发到结果页面
        request.setAttribute("user", user);
        request.getRequestDispatcher("/result.jsp").forward(request, response);
    }
}

四、表单数据获取方式对比

方法 说明 适用场景
request.getParameter("name") 获取单个参数值 文本框、单选框、下拉单选
request.getParameterValues("name") 获取多个参数值 复选框、多选列表
request.getParameterMap() 获取所有参数Map 批量处理参数
BeanUtils.populate() 自动封装到JavaBean 表单字段与JavaBean属性对应
@ModelAttribute (Spring MVC) 自动绑定参数 Spring框架中使用

五、表单验证实现

1. 客户端验证 (JavaScript)

javascript 复制代码
function validateForm() {
    var username = document.forms["myForm"]["username"].value;
    if (username == "") {
        alert("用户名必须填写");
        return false;
    }
    return true;
}

2. 服务器端验证 (Java)

java 复制代码
public class FormValidator {
    
    public static Map<String, String> validate(User user) {
        Map<String, String> errors = new HashMap<>();
        
        // 用户名验证
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            errors.put("username", "用户名不能为空");
        } else if (user.getUsername().length() < 3 || user.getUsername().length() > 20) {
            errors.put("username", "用户名长度应在3-20字符之间");
        }
        
        // 邮箱验证
        if (user.getEmail() != null && !user.getEmail().isEmpty()) {
            String emailRegex = "^[A-Za-z0-9+_.-]+@(.+)$";
            if (!user.getEmail().matches(emailRegex)) {
                errors.put("email", "邮箱格式不正确");
            }
        }
        
        return errors;
    }
}

3. 使用Hibernate Validator

java 复制代码
public class User {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度3-20字符")
    private String username;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码至少6位")
    private String password;
    
    @Email(message = "邮箱格式不正确")
    private String email;
    
    // getter/setter...
}

六、文件上传表单

1. 表单设置

html 复制代码
<form action="upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit" value="上传">
</form>

2. 使用Apache Commons FileUpload

java 复制代码
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        // 检查是否为multipart表单
        if (!ServletFileUpload.isMultipartContent(request)) {
            response.getWriter().print("错误:表单必须包含enctype=multipart/form-data");
            return;
        }
        
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        
        try {
            List<FileItem> items = upload.parseRequest(request);
            for (FileItem item : items) {
                if (!item.isFormField()) { // 文件字段
                    String fileName = new File(item.getName()).getName();
                    String filePath = getServletContext().getRealPath("/uploads") + File.separator + fileName;
                    File storeFile = new File(filePath);
                    item.write(storeFile);
                }
            }
            response.getWriter().print("文件上传成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

七、表单开发最佳实践

实践要点 说明
编码统一 始终使用UTF-8编码,避免乱码问题
双重验证 客户端验证提升体验,服务器端验证确保安全
防CSRF攻击 使用令牌(token)机制防止跨站请求伪造
防止SQL注入 使用PreparedStatement,避免拼接SQL
XSS防护 对用户输入进行过滤或转义
数据持久化 使用DAO模式分离数据访问逻辑
错误处理 友好的错误提示,避免暴露系统信息

八、MVC模式下的表单处理

java 复制代码
// Controller (Servlet)
@WebServlet("/user")
public class UserController extends HttpServlet {
    
    private UserService userService = new UserService();
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        // 1. 获取参数并封装
        User user = new User();
        BeanUtils.populate(user, request.getParameterMap());
        
        // 2. 验证
        Map<String, String> errors = Validator.validate(user);
        if (!errors.isEmpty()) {
            request.setAttribute("errors", errors);
            request.getRequestDispatcher("/register.jsp").forward(request, response);
            return;
        }
        
        // 3. 调用Service
        boolean success = userService.register(user);
        
        // 4. 返回结果
        if (success) {
            response.sendRedirect("success.jsp");
        } else {
            request.setAttribute("error", "注册失败,用户名可能已存在");
            request.getRequestDispatcher("/register.jsp").forward(request, response);
        }
    }
}

九、现代框架中的表单处理

Spring MVC 示例

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {
    
    @GetMapping("/register")
    public String showForm(Model model) {
        model.addAttribute("user", new User());
        return "register";
    }
    
    @PostMapping("/register")
    public String submitForm(@Valid @ModelAttribute("user") User user, 
                            BindingResult result, 
                            Model model) {
        if (result.hasErrors()) {
            return "register"; // 返回表单页面显示错误
        }
        userService.save(user);
        return "redirect:/success";
    }
}

十、常见问题解决方案

问题 原因 解决方案
中文乱码 编码不一致 request.setCharacterEncoding("UTF-8")
获取不到参数 表单enctype设置错误 普通表单不要用multipart/form-data
复选框获取单个值 使用getParameter而不是getParameterValues 区分单选和多选场景
文件上传失败 文件大小限制 配置最大文件大小限制
重复提交 用户刷新或回退 使用PRG模式(Post-Redirect-Get)
相关推荐
黎潇lulu2 小时前
Java运算符基础知识
java·开发语言
HAPPY酷2 小时前
C++中类常见的函数分类
java·开发语言·c++
小钻风33662 小时前
JWT初识
java·jwt·base64url
weixin_449173652 小时前
java使用poi保存表格和图片到word文件中
java·开发语言·word
好家伙VCC2 小时前
# 光计算驱动的编程范式革新:用Python实现光子神经网络模拟器在传统电子计算架构逼近物理极限的今天,**光计算**正
java·开发语言·python·神经网络
yqj2343 小时前
【无标题】
java·开发语言
Coder_Boy_3 小时前
JDK17_JDK21并发编程:资深架构常用模式+最佳实践
java·开发语言·spring boot·架构
最贪吃的虎3 小时前
windows上如何可视化访问并远程操作linux系统上运行的浏览器或者linux可视化桌面
java·linux·运维·windows·分布式·后端·架构