【Java项目脚手架系列】第二篇:JavaWeb项目脚手架

【Java项目脚手架系列】第二篇:JavaWeb项目脚手架

前言

在Java Web开发中,一个好的项目脚手架可以大大提高开发效率,减少重复工作。本篇文章将介绍一个基于Maven的JavaWeb项目脚手架,它包含了基础的Web开发配置和常用功能。

什么是JavaWeb项目脚手架?

JavaWeb项目脚手架是一个基于Maven的Web项目模板,它提供了:

  1. 标准的Web项目结构
  2. 基础的Web开发配置
  3. 常用功能组件
  4. 最佳实践示例

JavaWeb项目脚手架

1. 项目结构

复制代码
javaweb-scaffold/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── filter/
│   │   │           │   └── CharacterEncodingFilter.java
│   │   │           └── servlet/
│   │   │               ├── Error404Servlet.java
│   │   │               ├── Error500Servlet.java
│   │   │               └── HelloServlet.java
│   │   ├── resources/
│   │   │   └── log4j2.xml
│   │   └── webapp/
│   │       ├── WEB-INF/
│   │       │   └── web.xml
│   │       ├── error/
│   │       │   ├── 404.jsp
│   │       │   └── 500.jsp
│   │       └── index.jsp
│   └── test/
│       ├── java/
│       │   └── com/
│       │       └── example/
│       │           └── servlet/
│       │               └── HelloServletTest.java
│       └── resources/
├── docs/
│   └── 02-javaweb-scaffold.md
├── pom.xml
└── README.md

2. 核心文件内容

2.1 pom.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>javaweb-scaffold</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <servlet.version>4.0.1</servlet.version>
        <jsp.version>2.3.3</jsp.version>
        <jstl.version>1.2</jstl.version>
        <junit.version>5.8.2</junit.version>
        <mockito.version>4.5.1</mockito.version>
        <lombok.version>1.18.24</lombok.version>
        <log4j2.version>2.17.2</log4j2.version>
    </properties>

    <dependencies>
        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSP API -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>${jsp.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
            <scope>compile</scope>
        </dependency>

        <!-- JUnit 5 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Mockito -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- Log4j2 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/javaweb-scaffold</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
2.2 web.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <display-name>JavaWeb Scaffold</display-name>

    <!-- 字符编码过滤器 -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>com.example.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 错误页面配置 -->
    <error-page>
        <error-code>404</error-code>
        <location>/error/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.jsp</location>
    </error-page>
</web-app>
2.3 CharacterEncodingFilter.java
java 复制代码
package com.example.filter;

import javax.servlet.*;
import java.io.IOException;

public class CharacterEncodingFilter implements Filter {
    private String encoding;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        encoding = filterConfig.getInitParameter("encoding");
        if (encoding == null) {
            encoding = "UTF-8";
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}
2.4 HelloServlet.java
java 复制代码
package com.example.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("Hello from JavaWeb Scaffold!");
    }
}
2.5 Error404Servlet.java
java 复制代码
package com.example.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/error/404")
public class Error404Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.getRequestDispatcher("/error/404.jsp").forward(request, response);
    }
}
2.6 Error500Servlet.java
java 复制代码
package com.example.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/error/500")
public class Error500Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.getRequestDispatcher("/error/500.jsp").forward(request, response);
    }
}
2.7 index.jsp
jsp 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaWeb Scaffold</title>
</head>
<body>
    <div class="container">
        <h1>Welcome to JavaWeb Scaffold</h1>
        <p>Click <a href="hello">here</a> to test the HelloServlet.</p>
    </div>
</body>
</html>
2.8 log4j2.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Properties>
        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Property>
        <Property name="APP_LOG_ROOT">logs</Property>
    </Properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </Console>
        <RollingFile name="FileAppender" 
                     fileName="${APP_LOG_ROOT}/app.log"
                     filePattern="${APP_LOG_ROOT}/app-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="FileAppender"/>
        </Root>
    </Loggers>
</Configuration>
2.9 404.jsp
jsp 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>404 - Page Not Found</title>
    <style>
        .error-container {
            text-align: center;
            margin-top: 100px;
        }
        .error-code {
            font-size: 72px;
            color: #e74c3c;
        }
        .error-message {
            font-size: 24px;
            margin: 20px 0;
        }
        .home-link {
            color: #3498db;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <div class="error-container">
        <div class="error-code">404</div>
        <div class="error-message">Oops! The page you're looking for doesn't exist.</div>
        <a href="${pageContext.request.contextPath}/" class="home-link">Return to Home</a>
    </div>
</body>
</html>
2.10 500.jsp
jsp 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>500 - Internal Server Error</title>
    <style>
        .error-container {
            text-align: center;
            margin-top: 100px;
        }
        .error-code {
            font-size: 72px;
            color: #e74c3c;
        }
        .error-message {
            font-size: 24px;
            margin: 20px 0;
        }
        .error-details {
            color: #7f8c8d;
            margin: 20px 0;
        }
        .home-link {
            color: #3498db;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <div class="error-container">
        <div class="error-code">500</div>
        <div class="error-message">Internal Server Error</div>
        <div class="error-details">
            An unexpected error occurred. Please try again later.
        </div>
        <a href="${pageContext.request.contextPath}/" class="home-link">Return to Home</a>
    </div>
</body>
</html>
2.11 HelloServletTest.java
java 复制代码
package com.example.servlet;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;

import static org.mockito.Mockito.*;

class HelloServletTest {
    @Mock
    private HttpServletRequest request;
    
    @Mock
    private HttpServletResponse response;
    
    private HelloServlet servlet;
    private StringWriter stringWriter;
    private PrintWriter writer;

    @BeforeEach
    void setUp() throws Exception {
        MockitoAnnotations.openMocks(this);
        servlet = new HelloServlet();
        stringWriter = new StringWriter();
        writer = new PrintWriter(stringWriter);
        when(response.getWriter()).thenReturn(writer);
    }

    @Test
    void doGet_ShouldWriteHelloMessage() throws Exception {
        // When
        servlet.doGet(request, response);

        // Then
        verify(response).setContentType("text/html;charset=UTF-8");
        writer.flush();
        assertTrue(stringWriter.toString().contains("Hello from JavaWeb Scaffold!"));
    }
}

3. 使用说明

  1. 环境准备

    • JDK 8+
    • Maven 3.6+
    • Tomcat 8.5+
  2. 克隆项目

    bash 复制代码
    git clone git@gitee.com:zengqiang_wang/leecode-inteview-questions-journal.git
  3. 导入IDE

    • 推荐使用IntelliJ IDEA
    • 选择"Open as Maven Project"
  4. 运行项目

    bash 复制代码
    mvn tomcat7:run

    访问:http://localhost:8080/javaweb-scaffold/

4. 最佳实践

  1. 项目结构

    • 遵循标准的Web项目结构
    • 合理划分包层次
    • 保持代码整洁
  2. 编码规范

    • 统一使用UTF-8编码
    • 使用字符编码过滤器
    • 规范JSP页面编码
  3. 错误处理

    • 配置统一的错误页面
    • 记录详细的错误日志
    • 提供友好的错误提示
  4. 测试编写

    • 使用JUnit 5编写单元测试
    • 使用Mockito模拟Servlet环境
    • 测试覆盖核心功能

5. 常见问题

  1. IDEA社区版无Tomcat插件

    • 使用Maven插件运行
    • 安装Smart Tomcat插件
    • 配置Tomcat服务器
  2. 首页500错误

    • 检查JSTL依赖配置
    • 简化JSP页面内容
    • 配置错误页面
  3. 编码问题

    • 确保所有文件使用UTF-8编码
    • 配置字符编码过滤器
    • 检查JSP页面编码声明

6. 总结

这个JavaWeb项目脚手架提供了一个基础的Web开发环境,包含了常用的配置和功能。通过解决常见问题,我们可以快速搭建一个可用的Web项目。

7. 下期预告

下一期我们将介绍SpringMVC项目脚手架,它将基于本期项目进行扩展,添加Spring MVC相关功能,包括:

  • 标准的MVC架构
  • 统一响应处理
  • 统一异常处理
  • 参数校验
  • 文件上传
  • RESTful API支持

敬请期待!

相关推荐
LayZhangStrive6 分钟前
融360 一面
java·面试·后端开发
城管不管31 分钟前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
Java小白笔记35 分钟前
Windows系统免软件命令激活
java·网络·人工智能·windows·ai·ai编程
爱敲键盘的猴子43 分钟前
深入理解 Java HashMap
java·hashmap
霸道流氓气质44 分钟前
Java开发者AI编程常用MCP、Skills、Rules全景汇总
java·开发语言·ai编程
天涯醉青楼1 小时前
Spring Boot 接口返回 Bean 时字段名“变形”的深度剖析与解决方案
java
zoujiahui_20181 小时前
Python 包与环境管理工具 uv
开发语言·python·uv
步行cgn1 小时前
MyBatis 高级映射与延迟加载完全指南
java·tomcat·mybatis
thefool1122661 小时前
从中序与后序遍历序列构造二叉树
java
吴声子夜歌1 小时前
Java面试题——JVM(二)
java·开发语言·jvm