【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 [email protected]: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支持

敬请期待!

相关推荐
Echo``10 分钟前
19:常见的Halcon数据格式
java·linux·图像处理·人工智能·windows·机器学习·视觉检测
Rubypyrrha15 分钟前
Spring框架的设计目标,设计理念,和核心是什么 ?
java·spring
佩奇的技术笔记17 分钟前
Java学习手册:Spring 多数据源配置与管理
java·spring
DonciSacer1 小时前
第一章-Rust入门
开发语言·后端·rust
西京刀客1 小时前
golang常用库之-标准库text/template
开发语言·后端·golang
落榜程序员1 小时前
浅拷贝和深拷贝的区别
java·开发语言
KrityCat1 小时前
查看并升级Docker里面Jenkins的Java17到21版本
java·docker·容器·jdk·jenkins
_UMR_2 小时前
SpringBoot集成CXF框架,实现WebService
java·spring boot
renhl2522 小时前
C++11新特性_委托构造函数
java·前端·c++
purrrew2 小时前
【Java ee初阶】多线程(7)
java·开发语言