嵌入式Tomcat学习-第五天

写在前面

什么是嵌入式 Tomcat?

嵌入式 Tomcat 是将 Apache Tomcat 服务器作为库文件集成到 Java 应用程序中的技术方案。它允许开发者通过编程方式直接启动、配置和管理 Tomcat,无需依赖独立安装的 Tomcat 服务器,适用于构建轻量级、自包含的 Web 应用或微服务。

版本特性(11.0.3)

  • Servlet/JSP 规范支持
    支持 Servlet 6.0 和 JSP 4.0 规范(基于 Jakarta EE 10 平台)。
  • 轻量级嵌入
    通过 tomcat-embed-core 等依赖包实现核心功能集成,无需完整 Tomcat 安装。
  • Java 版本要求
    最低要求 Java 17 及以上版本。
  • 性能优化
    改进的 HTTP/2 支持、连接器性能调优及内存管理优化。

核心优势

  • 简化部署
    应用与服务器一体化,直接打包为可执行 JAR 文件,适合云原生场景。
  • 灵活配置
    通过代码动态配置端口、上下文路径、SSL 等参数,无需 server.xml 文件。
  • 开发便捷
    与 Spring Boot、Micronaut 等框架无缝集成,快速构建独立 Web 服务。
  • 资源占用低
    仅加载必要的组件,启动速度快,适合资源受限环境。

典型应用场景

  • 微服务架构中的独立服务节点
  • 快速原型开发或测试环境
  • 命令行工具集成 Web 接口
  • 需要定制化 Web 容器行为的场景

为springmvc配置validator

pom.xml新增validator依赖

image-agkp.png

<?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.lhstack.tomcat</groupId>
    <artifactId>tomcat-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>4.0.0</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>8.0.2.Final</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>6.2.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.24.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.24.3</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>11.0.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>11.0.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-websocket -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>11.0.3</version>
        </dependency>

    </dependencies>

    <repositories>
        <repository>
            <id>aliyun</id>
            <name>阿里云</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

</project>

spring-mvc.xml配置validator

image-fyct.png

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--  2025-02-22 新增 注册validator bean,设置 providerClass为HibernateValidator实现 -->
    <bean name="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
    </bean>

    <!--  设置validator,指向validator bean  -->
    <mvc:annotation-driven validator="validator" />

    <!--  2025-02-22 新增 设置jsp的视图解析器,对Controller返回的字符串自动组装成/WEB-INF/jsp/字符串.jsp  -->
    <mvc:view-resolvers>
        <mvc:jsp prefix="/WEB-INF/jsp/" suffix=".jsp"/>
    </mvc:view-resolvers>

    <context:component-scan base-package="com.lhstack.tomcat.controller">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

</beans>

配置全局异常拦截器

获取参数名,需要修改pom.xml,配置编译保留参数名

image-ybqa.png

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <target>${maven.compiler.target}</target>
                    <source>${maven.compiler.source}</source>
                    <compilerArgument>-parameters</compilerArgument>
                </configuration>
            </plugin>
        </plugins>
    </build>

image-gwfr.png

GlobalExceptionHandlers

package com.lhstack.tomcat.controller;

import org.springframework.context.MessageSourceResolvable;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import java.util.Map;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandlers {


    @ExceptionHandler(exception = MethodArgumentNotValidException.class)
    public Map<String, Object> validatorExceptionHandler(MethodArgumentNotValidException e) {
        Map<String, String> errors = e.getBindingResult().getAllErrors().stream()
                .collect(Collectors.toMap(ObjectError::getObjectName, ObjectError::getDefaultMessage, (o1, o2) -> o2));
        return Map.of("code", "500", "msg", "校验异常", "errors", errors);
    }

    @ExceptionHandler(exception = HandlerMethodValidationException.class)
    public Map<String, Object> exceptionHandler(HandlerMethodValidationException e) {
        Map<Object, String> errors = e.getParameterValidationResults().stream()
                .collect(Collectors.toMap(item -> item.getMethodParameter().getParameterName(),
                        item -> item.getResolvableErrors().stream().map(MessageSourceResolvable::getDefaultMessage)
                                .collect(Collectors.joining(",")), (o1, o2) -> o2));
        return Map.of("code", "500", "msg", "校验异常", "errors", errors);
    }
}

编写代码测试

image-ygpa.png

package com.lhstack.tomcat.controller;

import jakarta.validation.constraints.NotEmpty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("test")
public class TestController {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);

    @GetMapping
    public Map<String,String> test(@RequestParam(name = "value") @NotEmpty(message = "value不能为空") String value){
        LOGGER.info("test: {}",value);
        return Map.of("msg","hello world");
    }
}

image-exzt.png

集成spring-security

pom增加spring-security依赖


        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>6.4.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>6.4.3</version>
        </dependency>

配置security

web.xml

image-xakz.png

image-qspt.png

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <welcome-file-list>
        <welcome-file>index</welcome-file>
    </welcome-file-list>
    
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-*.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <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>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

spring-security.xml

image-iapo.png

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security  https://www.springframework.org/schema/security/spring-security.xsd">

    <security:http entry-point-ref="authenticationEntryPoint">
        <security:intercept-url pattern="/**" access="isAuthenticated()"/>
        <security:csrf disabled="true"/>
        <security:headers disabled="true"/>
        <security:form-login  authentication-failure-handler-ref="authenticationFailureHandler" authentication-success-handler-ref="authenticationSuccessHandler" />
    </security:http>

    <bean name="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
        <constructor-arg name="defaultTargetUrl" value="/"/>
    </bean>
    <bean name="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
        <constructor-arg name="defaultFailureUrl" value="/login?error=error"/>
    </bean>

    <bean name="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint" >
        <constructor-arg value="/login" />
    </bean>

    <security:user-service>
        <security:user name="admin" authorities="ADMIN" password="{noop}123456"/>
    </security:user-service>

</beans>

启动项目并测试

image-hgxx.png

image-mkjc.png

自动重定向到/login

image-pabj.png

输入错误的密码,自动重定向到/login页面

image-dwnr.png

image-cfph.png

输入正确的密码

image-evuq.png

image-mknw.png

结尾

tomcat-demo-fnos.zip

今天介绍了如何在嵌入式tomcat中增加validator以及全局异常拦截器和spring-security支持,让这个demo的功能逐步完善


嵌入式Tomcat学习-第五天
https://blog.lhstack.xyz/archives/qian-ru-shi-tomcatxue-xi-di-wu-tian
作者
lhstack
发布于
2025年03月12日
许可协议