Spring+SprinMVC+MyBatis注解方式简易模板

Spring+SprinMVC+MyBatis注解方式简易模板代码Demo GitHub访问 ssm-tpl-anno

一、数据准备

创建数据库test,执行下方SQL创建表ssm-tpl-cfg

/*
 Navicat Premium Data Transfer

 Source Server         : 127.0.0.1
 Source Server Type    : MySQL
 Source Server Version : 80030
 Source Host           : 127.0.0.1:3306
 Source Schema         : test

 Target Server Type    : MySQL
 Target Server Version : 80030
 File Encoding         : 65001

 Date: 17/10/2022 00:52:07
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for ssm-tpl-cfg
-- ----------------------------
DROP TABLE IF EXISTS `ssm-tpl-cfg`;
CREATE TABLE `ssm-tpl-cfg` (
  `id` bigint NOT NULL COMMENT '主键编号',
  `name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '测试名称',
  PRIMARY KEY (`id`)
) COMMENT '初始SSM表结构数据' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of ssm-tpl-cfg
-- ----------------------------
BEGIN;
INSERT INTO `ssm-tpl-cfg` (`id`, `name`) VALUES (2210162246100000, '左翰林');
INSERT INTO `ssm-tpl-cfg` (`id`, `name`) VALUES (2210162257100000, '刘卓神');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

二、代码实现

2.1 pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.tpl.ssm.anno</groupId>
    <artifactId>ssm-tpl-anno</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <spring_version>5.1.18.RELEASE</spring_version>
        <jackson_version>2.9.7</jackson_version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-annotation</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.15.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.15.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.36</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.findbugs</groupId>
            <artifactId>annotations</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.25</version>
        </dependency>
    </dependencies>
</project>

2.2 Spring和Mybatis配置

package com.tpl.ssm.anno.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/*
 * Spring配置类
 *
 * <!-- 扫描service -->
 * <context:component-scan base-package="com.tpl.ssm.cfg.service"/>
 */
@ComponentScan(basePackages = {"com.tpl.ssm.anno.service"}, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = org.springframework.stereotype.Controller.class)
})
@EnableTransactionManagement
@Configuration
public class SpringConfig {

    private static final Logger logger = LoggerFactory.getLogger(SpringConfig.class);

    /*
     * <!-- 配置数据库连接池 -->
     * <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
     *     <!-- 四大连接参数 -->
     *     <property name="driverClassName" value="${jdbc.driverClassName}"/>
     *     <property name="url" value="${jdbc.url}"/>
     *     <property name="username" value="${jdbc.username}"/>
     *     <property name="password" value="${jdbc.password}"/>
     *     <!-- 连接池配置信息 -->
     *     <property name="initialSize" value="${jdbc.initialSize}"/>
     *     <property name="minIdle" value="${jdbc.minIdle}"/>
     *     <property name="maxActive" value="${jdbc.maxActive}"/>
     *     <property name="maxWait" value="${jdbc.maxWait}"/>
     *     <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
     *     <property name="timeBetweenEvictionRunsMillis" value="60000"/>
     *     <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
     *     <property name="minEvictableIdleTimeMillis" value="300000" />
     *     <!-- Druid用来测试连接是否可用的SQL语句,默认值每种数据库都不相同-->
     *     <property name="validationQuery" value="SELECT 'x'" />
     *     <!-- 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除. -->
     *     <property name="testWhileIdle" value="true" />
     *     <!-- 指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 -->
     *     <property name="testOnBorrow" value="false" />
     *     <!-- 指明是否在归还到池中前进行检验 -->
     *     <property name="testOnReturn" value="false" />
     *     <!-- 配置监控统计拦截的filters -->
     *     <property name="filters" value="wall,stat" />
     * </bean>
     */
    @Bean(name = "dataSource")
    public DruidDataSource druidDataSource() {
        // 基本属性 url、user、password
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/test");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");

        // 配置初始化大小、最小、最大
        druidDataSource.setInitialSize(10);
        druidDataSource.setMinIdle(10);
        druidDataSource.setMaxActive(50);

        // 配置获取连接等待超时的时间
        druidDataSource.setMaxWait(60000);
        // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);

        // 配置一个连接在池中最小生存的时间,单位是毫秒
        druidDataSource.setMinEvictableIdleTimeMillis(300000);

        druidDataSource.setValidationQuery("SELECT 1");
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);

        // 打开PSCache,并且指定每个连接上PSCache的大小
        // 如果用Oracle,则把poolPreparedStatements配置为true,
        // mysql可以配置为false。
        druidDataSource.setPoolPreparedStatements(true);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(20);

        // 配置监控统计拦截的filters
        try {
            druidDataSource.setFilters("wall,stat");
        } catch (SQLException e) {
            logger.error("配置监控统计拦截的filters error: ", e);
        }
        return druidDataSource;
    }

    /*
     * <!-- 配置sessionFactory -->
     * <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
     *     <!-- 注入数据源 -->
     *     <property name="dataSource" ref="dataSource"/>
     *     <!-- mapper文件位置 -->
     *     <property name="mapperLocations" value="classpath:mapper/*DAO.xml"/>
     *     <!-- mybatis核心配置文件位置 -->
     *     <property name="configLocation" value="classpath:config/mybatis-config.xml"/>
     * </bean>
     */
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactoryBean() {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setMapperLocations(resolveMapperLocations());
        sqlSessionFactory.setDataSource(druidDataSource());
        /*
         * <?xml version="1.0" encoding="UTF-8" ?>
         * <!DOCTYPE configuration
         *         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         *         "http://mybatis.org/dtd/mybatis-3-config.dtd">
         * <configuration>
         *
         *     <!-- 配置信息 -->
         *     <settings>
         *         <!-- 映射下划线到驼峰命名 -->
         *         <setting name="mapUnderscoreToCamelCase" value="true"/>
         *         <!-- 配置开启二级缓存 -->
         *         <setting name="cacheEnabled" value="true"/>
         *         <!-- 开启控制台打印SQL -->
         *         <setting name="logImpl" value="STDOUT_LOGGING"/>
         *     </settings>
         *
         *     <!-- 别名 -->
         *     <typeAliases>
         *         <package name="com.tpl.ssm.cfg.entity"/>
         *     </typeAliases>
         * </configuration>
         */
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisConfiguration.setMapUnderscoreToCamelCase(true);
        mybatisConfiguration.setCacheEnabled(true);
        mybatisConfiguration.setLogImpl(StdOutImpl.class);
        mybatisConfiguration.getTypeAliasRegistry().registerAliases("com.tpl.ssm.anno.entity");

        sqlSessionFactory.setConfiguration(mybatisConfiguration);
        return sqlSessionFactory;
    }

    // https://wenku.baidu.com/view/1b9ade1640323968011ca300a6c30c225901f0c2.html
    public Resource[] resolveMapperLocations() {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        List<String> mapperLocations = new ArrayList<>();
        mapperLocations.add("classpath:mapper/*DAO.xml");
        List<Resource> resources = new ArrayList<>();
        for (String mapperLocation : mapperLocations) {
            Resource[] mappers = new Resource[0];
            try {
                mappers = resolver.getResources(mapperLocation);
            } catch (IOException e) {
                e.printStackTrace();
            }
            resources.addAll(Arrays.asList(mappers));
        }
        return resources.toArray(new Resource[0]);
    }

    /*
     * <!-- 配置扫描mapper生成代理对象 -->
     * <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     *     <property name="basePackage" value="com.tpl.ssm.cfg.dao"/>
     *     <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
     * </bean>
     */
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.tpl.ssm.anno.dao");
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        return mapperScannerConfigurer;
    }

    /* 事务管理器配置
     * <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     *     <property name="dataSource" ref="dataSourceProxy"/>
     * </bean>
     */
    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

}

2.3 SpringMVC配置

package com.tpl.ssm.anno.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/* 开启controller注解支持
 * 注意事项请参考:http://jinnianshilongnian.iteye.com/blog/1762632
 *
 * <context:component-scan base-package="com.tpl.ssm.cfg.controller"/>
 */
@ComponentScan(basePackages = {
        "com.tpl.ssm.anno.controller"
}, includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = org.springframework.stereotype.Controller.class),
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = org.springframework.web.bind.annotation.ControllerAdvice.class)
}, useDefaultFilters = false)
@EnableWebMvc
@Configuration
// <import resource="spring-mvc-xxx.xml"/>
// @Import(value = {SpringMvcXxxConfig.class})
public class SpringMVCConfig implements WebMvcConfigurer {

    /* <!-- 配置SpringMVC视图解析器 -->
     * <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     *     <property name="prefix" value="/pages/"/>
     *     <property name="suffix" value=".jsp"/>
     * </bean>
     */
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
        resolver.setPrefix("/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    /* <!-- 释放静态资源文件 -->
     * <mvc:resources mapping="/js/" location="/js/**"/>
     * <mvc:resources mapping="/css/" location="/css/**"/>
     * <mvc:resources mapping="/images/" location="/images/**"/>
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/").addResourceLocations("/js/**");
        registry.addResourceHandler("/css/").addResourceLocations("/css/**");
        registry.addResourceHandler("/images/").addResourceLocations("/images/**");
    }

    // 文件解析器
    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
        // maxUploadSizePerFile:单个文件大小限制(byte)
        // maxUploadSize:整个请求大小限制(byte)
        commonsMultipartResolver.setMaxUploadSizePerFile(10 * 1024 * 1024); // 10M
        commonsMultipartResolver.setMaxUploadSize(100 * 1024 * 1024); // 100M
        return commonsMultipartResolver;
    }

}

2.4 web.xml配置

package com.tpl.ssm.anno.config;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

/**
 * Web应用启动入口
 * <p/>
 * <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 * xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 * xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 * http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
 * </web-app>
 */
public class WebInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // 父容器配置
        AnnotationConfigWebApplicationContext springCtx = new AnnotationConfigWebApplicationContext();
        springCtx.setDisplayName("ssm-tpl-anno"); // 部署应用的名称 <display-name>ssm-tpl-anno</display-name>

        /*
         * <!-- Spring配置文件开始  -->
         * <context-param>
         *     <param-name>contextConfigLocation</param-name>
         *     <param-value>
         *         classpath:spring-config.xml
         *     </param-value>
         * </context-param>
         * <listener>
         *     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
         * </listener>
         * <!-- Spring配置文件结束 -->
         */
        springCtx.register(SpringConfig.class);
        // 通过监听器加载配置信息
        servletContext.addListener(new ContextLoaderListener(springCtx));

        /* 可以使用RequestContextHolder.currentRequestAttributes() 获取到请求的attr
         * <listener>
         *     <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
         * </listener>
         */
        servletContext.addListener(org.springframework.web.context.request.RequestContextListener.class);

        // 子容器配置
        AnnotationConfigWebApplicationContext mvcCtx = new AnnotationConfigWebApplicationContext();
        /*
         * <!-- SpringMVC配置文件开始  -->
         * <servlet>
         *     <servlet-name>springMVC</servlet-name>
         *     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
         *     <init-param>
         *         <param-name>contextConfigLocation</param-name>
         *         <param-value>classpath:spring-mvc.xml</param-value>
         *     </init-param>
         *     <load-on-startup>1</load-on-startup>
         *     <async-supported>true</async-supported>
         * </servlet>
         * <servlet-mapping>
         *     <servlet-name>springMVC</servlet-name>
         *     <url-pattern>/</url-pattern>
         * </servlet-mapping>
         * <!-- SpringMVC配置文件结束  -->
         */
        mvcCtx.register(SpringMVCConfig.class);
        ServletRegistration.Dynamic servlet = servletContext.addServlet(
                "DispatcherServlet",
                new DispatcherServlet(mvcCtx));
        servlet.setLoadOnStartup(1);
        servlet.setAsyncSupported(true);
        servlet.addMapping("/");

        /*
         * <!-- 设置servlet编码开始 -->
         * <filter>
         *     <filter-name>CharacterEncodingFilter</filter-name>
         *     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
         *     <async-supported>true</async-supported>
         *     <init-param>
         *         <param-name>encoding</param-name>
         *         <param-value>UTF-8</param-value>
         *     </init-param>
         *     <init-param>
         *         <param-name>forceEncoding</param-name>
         *         <param-value>true</param-value>
         *     </init-param>
         * </filter>
         * <filter-mapping>
         *     <filter-name>CharacterEncodingFilter</filter-name>
         *     <url-pattern>/*</url-pattern>
         * </filter-mapping>
         * <!-- 设置servlet编码结束 -->
         */
        FilterRegistration.Dynamic encodingFilter = servletContext.addFilter(
                "CharacterEncodingFilter",
                new CharacterEncodingFilter("UTF-8", true));
        encodingFilter.setAsyncSupported(true);
        encodingFilter.addMappingForUrlPatterns(null, false, "/*");
    }
}

2.5 Entity

package com.tpl.ssm.anno.entity;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonIgnore;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 测试实体
 */
public class TestEntity {

    /**
     * 主键编号
     */
    private Long id;

    /**
     * 测试名称
     */
    private String name;

    private JSONObject flowImg;
    private String flowImgStr;


    /**
     * 扩展字段
     */
    @JsonIgnore
    @TableField(exist = false)
    private Map<String, Object> ext = new LinkedHashMap<>(5);

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Map<String, Object> getExt() {
        return ext;
    }

    public void setExt(Map<String, Object> ext) {
        this.ext = ext;
    }

    public JSONObject getFlowImg() {
        return flowImg;
    }

    public void setFlowImg(JSONObject flowImg) {
        this.flowImg = flowImg;
    }

    public String getFlowImgStr() {
        return flowImgStr;
    }

    public void setFlowImgStr(String flowImgStr) {
        this.flowImgStr = flowImgStr;
    }
}

2.6 Controller

package com.tpl.ssm.anno.controller;

import com.tpl.ssm.anno.entity.TestEntity;
import com.tpl.ssm.anno.service.TestService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

/**
 * 1. Spring5.1.x -> jackson2.9.x
 * 2.The origin server did not find a current representation for the target resource
 * 原因是WEB-INF只能转发进去, 重定向是进不去的
 */
@Controller
@RequestMapping("/test")
public class TestController {

    private final TestService testService;

    public TestController(TestService testService) {
        this.testService = testService;
    }

    @GetMapping("/")
    public String listTests(TestEntity test, Model model) {
        List<TestEntity> tests = testService.listTests(test);
        model.addAttribute("tests", tests);
        return "test";
    }

    @PostMapping("/save")
    public String saveTest(@RequestBody TestEntity test) {
        testService.saveTest(test);
        return "redirect:/test/";
    }

    @PostMapping("/modify")
    public String modifyTest(TestEntity test) {
        testService.modifyTest(test);
        return "redirect:/test/";
    }

    @RequestMapping("/remove")
    public String removeTest(TestEntity test) {
        testService.removeTest(test);
        return "redirect:/test/";
    }

}

2.7 Service

package com.tpl.ssm.anno.service;

import com.tpl.ssm.anno.entity.TestEntity;

import java.util.List;

public interface TestService {

    /**
     * 测试集
     *
     * @param cond 查询条件
     * @return 测试集
     */
    public List<TestEntity> listTests(TestEntity cond);

    /**
     * 单一测试实体
     *
     * @param cond 查询条件
     * @return 测试实体
     */
    public TestEntity singleTest(TestEntity cond);

    /**
     * 新增测试记录
     *
     * @param cond 查询条件
     * @return 受影响的条数
     */
    public boolean saveTest(TestEntity cond);

    /**
     * @param cond 查询条件
     * @return 受影响的条数
     */
    public boolean modifyTest(TestEntity cond);

    /**
     * 删除一条测试记录
     *
     * @param cond 查询条件
     * @return 受影响的条数
     */
    public boolean removeTest(TestEntity cond);

    /**
     * 删除多条测试记录
     *
     * @param testIds 测试实体主键集
     * @return 受影响的条数
     */
    public boolean removeTests(List<Long> testIds);

}
package com.tpl.ssm.anno.service.impl;

import com.tpl.ssm.anno.dao.TestDAO;
import com.tpl.ssm.anno.entity.TestEntity;
import com.tpl.ssm.anno.service.TestService;
import com.tpl.ssm.anno.util.MajorKeyUtil;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TestServiceImpl implements TestService {

    private final TestDAO testDAO;

    public TestServiceImpl(TestDAO testDAO) {
        this.testDAO = testDAO;
    }

    @Override
    public List<TestEntity> listTests(TestEntity cond) {
        return testDAO.listTests(cond);
    }

    @Override
    public TestEntity singleTest(TestEntity cond) {
        return testDAO.singleTest(cond);
    }

    @Override
    public boolean saveTest(TestEntity cond) {
        cond.setId(MajorKeyUtil.idSeq());
        cond.setFlowImgStr(cond.getFlowImg().toString());
        return testDAO.insertTest(cond) > 0;
    }

    @Override
    public boolean modifyTest(TestEntity cond) {
        return testDAO.updateTest(cond) > 0;
    }

    @Override
    public boolean removeTest(TestEntity cond) {
        return testDAO.deleteTest(cond) > 0;
    }

    @Override
    public boolean removeTests(List<Long> testIds) {
        return testDAO.deleteTests(testIds) > 0;
    }
}

2.8 DAO

package com.tpl.ssm.anno.dao;

import com.tpl.ssm.anno.entity.TestEntity;

import java.util.List;

/**
 * 测试DAO
 * <p>
 * 1.查询测试记录列表 - listTests
 * 2.查询单个测试记录 - singleTest
 * 3.新增测试记录 - insertTest
 * 4.修改测试记录 - updateTest
 * 5.删除测试记录 - deleteTest
 * 6.根据主键集删除测试记录 - deleteTests
 */
public interface TestDAO {

    /**
     * 测试集
     *
     * @param cond 查询条件
     * @return 测试集
     */
    public List<TestEntity> listTests(TestEntity cond);

    /**
     * 单一测试实体
     *
     * @param cond 查询条件
     * @return 测试实体
     */
    public TestEntity singleTest(TestEntity cond);

    /**
     * 新增测试记录
     *
     * @param cond 查询条件
     * @return 受影响的条数
     */
    public int insertTest(TestEntity cond);

    /**
     * @param cond 查询条件
     * @return 受影响的条数
     */
    public int updateTest(TestEntity cond);

    /**
     * 删除一条测试记录
     *
     * @param cond 查询条件
     * @return 受影响的条数
     */
    public int deleteTest(TestEntity cond);

    /**
     * 删除多条测试记录
     *
     * @param testIds 测试实体主键集
     * @return 受影响的条数
     */
    public int deleteTests(List<Long> testIds);

}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tpl.ssm.anno.dao.TestDAO">

    <!-- 基础查询 sql 片段 -->
    <sql id="baseSelect">
        SELECT id, name
    </sql>

    <!-- 基础查询 where 片段 -->
    <sql id="baseWhere">
        <if test="id != null">
            AND id = #{id}
        </if>
        <if test="name != null and name != ''">
            AND name like CONCAT('%', #{name})
        </if>
    </sql>

    <!-- 查询测试记录列表 -->
    <select id="listTests" parameterType="com.tpl.ssm.anno.entity.TestEntity" resultType="com.tpl.ssm.anno.entity.TestEntity">
        <include refid="baseSelect"/>
        FROM `ssm-tpl-cfg`
        WHERE
        1 = 1
        <include refid="baseWhere"/>
    </select>

    <!-- 查询单个测试记录 -->
    <select id="singleTest" parameterType="com.tpl.ssm.anno.entity.TestEntity" resultType="com.tpl.ssm.anno.entity.TestEntity">
        <include refid="baseSelect"/>
        FROM `ssm-tpl-cfg`
        WHERE
        1 = 1
        <include refid="baseWhere"/>
        limit 1
    </select>

    <!-- 新增测试记录 -->
    <insert id="insertTest" parameterType="com.tpl.ssm.anno.entity.TestEntity">
        INSERT INTO `ssm-tpl-cfg`(id, name, flow_img)
        VALUES (#{id}, #{name}, #{flowImgStr})
    </insert>

    <!-- 修改测试记录 -->
    <update id="updateTest" parameterType="com.tpl.ssm.anno.entity.TestEntity">
        UPDATE `ssm-tpl-cfg`
        SET
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        WHERE id = #{id}
    </update>

    <!-- 删除测试记录 -->
    <delete id="deleteTest" parameterType="com.tpl.ssm.anno.entity.TestEntity">
        DELETE
        FROM `ssm-tpl-cfg`
        WHERE 1 = 1
        <include refid="baseWhere"/>
    </delete>

    <!-- 根据主键集删除测试记录 -->
    <delete id="deleteTests" parameterType="long">
        DELETE
        FROM `ssm-tpl-cfg`
        WHERE id in
        <foreach collection="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </delete>
</mapper>

2.9 webapps/pages/test.jsp

<%--
  Created by IntelliJ IDEA.
  User: wangfeihu
  Date: 2022/10/16
  Time: 18:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>CRUD TEST</title>
</head>
<body>
<table>
    <c:forEach items="${tests}" var="test">
        <tr>
            <td>${test.id}</td>
            <td>${test.name}</td>
            <td>
                <button onclick="let modifyForms = document.getElementsByName('modifyForm'); modifyForms.forEach(item => item.style.display = 'none'); document.getElementById('form${test.id}').style.display = 'inline'">修改</button>
                <button onclick="location.href='${pageContext.request.contextPath}/test/remove?id=${test.id}'">删除</button>
            </td>
            <td>
                <form id="form${test.id}" name="modifyForm" action="${pageContext.request.contextPath}/test/modify" method="post" style="display: none">
                    <input hidden name="id" value="${test.id}">
                    <input name="name" value="${test.name}">
                    <button type="submit">确认修改</button>
                </form>
            </td>
        </tr>
    </c:forEach>
</table>

<form action="${pageContext.request.contextPath}/test/save" method="post">
    <label>
        <input name="name" id="name" placeholder="请输入测试名称~">
    </label>
    <button type="submit">提交</button>
</form>
</body>
</html>

2.10 配置项目访问路径

配置项目访问路径

三、访问测试

访问测试

一个简单的基于注解的增删改查就实现了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/336928.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HCIP-BGP实验3

实验步骤 配置IP地址 R1 [r1]int g0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [r1-GigabitEthernet0/0/0]int loopback0 [r1-LoopBack0]ip add 192.168.1.1 24 [r1-LoopBack0]int loopback1 [r1-LoopBack1]ip add 192.168.2.1 24 [r1-LoopBack1]int loopback3 [r1-…

OCS2 入门教程(六)- Double Integrator

系列文章目录 前言 双积分器示例是我们最简单的问题。它模拟了一个沿 x 方向移动的一维点质量。模型是线性的&#xff0c;成本函数是二次函数。目标点通过参考管理器模块设置为二次成本。 一、查看文件结构 1.1 ocs2_double_integrator 文件夹 . ├── auto_generated ├─…

LSTM时间序列预测

本文借鉴了数学建模清风老师的课件与思路&#xff0c;可以点击查看链接查看清风老师视频讲解&#xff1a;【1】演示&#xff1a;基于LSTM深度学习网络预测时间序列&#xff08;MATLAB工具箱&#xff09;_哔哩哔哩_bilibili % Forecast of time series based on LSTM deep learn…

Pyro —— Velocity Voxel Scale

Velocity Voxel Scale是H19.5引入的新参数&#xff0c;该参数可单独定义volume和速度体素&#xff1b;根据参数设置&#xff0c;可观察到模拟时间的显著变化&#xff1b; Velocity Voxel Scale对DOP和SOP均可用&#xff1b;对DOP设置&#xff0c;该参数在Smoke Object&#xf…

Java安全 CC链1分析

Java安全之CC链1分析 什么是CC链环境搭建jdk下载idea配置创建项目 前置知识Transformer接口ConstantTransformer类invokerTransformer类ChainedTransformer类 构造CC链1CC链1核心demo1demo1分析 寻找如何触发CC链1核心TransformedMap类AbstractInputCheckedMapDecorator类readO…

RT-Thread 瑞萨 智能家居网络开发:RA6M3 HMI Board 以太网+GUI技术实践

不用放大了&#xff0c; 我在包里找到张不小的…… 以太网HMI线下培训-环境准备 这是社群的文档&#xff1a;【腾讯文档】以太网线下培训&#xff08;HMI-Board&#xff09; https://docs.qq.com/doc/DY0FIWFVuTEpORlNn 先介绍周六的培训是啥&#xff0c;然后再介绍一下要准…

赛车游戏简单单车C语言版

#include<stdio.h> #include<easyx.h> #include<time.h>#define WIDTH 512 #define HEIGHT 768//定义一个汽车类 struct FCar {//坐标float x, y;// 汽车种类int type;//汽车速度float speed; };//定义全局变量 图片坐标 IMAGE BG_IMG; //背景图片坐标 float…

[小程序]使用代码渲染页面

一、条件渲染 1.单个控制 使用wx:if"{{条件}}"来判断是否需要渲染这段代码&#xff0c;同时可以结合wx:elif和wx:else来判断 <view wx:if"{{type0}}">0</view> <view wx:elif"{{type1}}">1</view> <view wx:else>…

linux网络协议栈2--网络包接收发送流程

上文我们讲了报文格式&#xff0c;应该对数据传输格式有了一定了解&#xff0c;这篇文章主要讲述的是网络包接收和发送的流程&#xff0c;主要是大方面来介绍。 网络包接收流程 当网络数据帧通过网络传输到达网卡时&#xff0c;网卡会将网络数据帧通过DMA的方式放到环形缓冲区…

nginx日志分割

日志切割是线上常见的操作&#xff0c;能够控制单个日志文件的大小&#xff0c;便于对日志进行管理 给nginx主进程发送一个重新打开的信号&#xff0c;让nginx重新生成新的日志文件 nginx -s reopen 这个命令等同于kill -USR1 cat nginx.pid 切割日志文件shell命令 #!/bin/bas…

Flink处理函数(3)—— 窗口处理函数

窗口处理函数包括&#xff1a;ProcessWindowFunction 和 ProcessAllWindowFunction 基础用法 stream.keyBy( t -> t.f0 ).window( TumblingEventTimeWindows.of(Time.seconds(10)) ).process(new MyProcessWindowFunction()) 这里的MyProcessWindowFunction就是ProcessWi…

rk1126, 实现 yolov8 目标检测

基于 RKNN 1126 实现 yolov8 目标检测 Ⓜ️ RKNN 模型转换 ONNX yolo export model./weights/yolov8s.pt formatonnx导出 RKNN 这里选择输出 concat 输入两个节点 onnx::Concat_425 和 onnx::Concat_426 from rknn.api import RKNNONNX_MODEL ./weights/yolov8s.onnxRKNN_MOD…

C语言练习day8

变种水仙花 变种水仙花_牛客题霸_牛客网 题目&#xff1a; 思路&#xff1a;我们拿到题目的第一步可以先看一看题目给的例子&#xff0c;1461这个数被从中间拆成了两部分&#xff1a;1和461&#xff0c;14和61&#xff0c;146和1&#xff0c;不知道看到这大家有没有觉得很熟…

Spring Boot整合Redis的高效数据缓存实践

引言 在现代Web应用开发中&#xff0c;数据缓存是提高系统性能和响应速度的关键。Redis作为一种高性能的缓存和数据存储解决方案&#xff0c;被广泛应用于各种场景。本文将研究如何使用Spring Boot整合Redis&#xff0c;通过这个强大的缓存工具提高应用的性能和可伸缩性。 整合…

对#多种编程语言 性能的研究和思考 go/c++/rust java js ruby python

对#多种编程语言 性能的研究和思考 打算学习一下rust 借着这个契机 简单的写了计算圆周率代码的各种语言的版本 比较了一下性能 只比拼单线程简单计算能力 计算十亿次循环 不考虑多线程 go/c/rust java js ruby python 耗时秒数 1:1:1:22:3:250:450 注&#xff1a;能启用则启…

Python 自动化测试:数据驱动

软件质量。这种测试&#xff0c;在功能测试中非常耗费人力物力&#xff0c;但是在自动化中&#xff0c;却比较好实现&#xff0c;只要实现了测试操作步骤&#xff0c;然后将多组测试数据以数据驱动的形式注入&#xff0c;就可以实现了。 前面文章学习了参数化&#xff0c;当数…

【机组】算术逻辑单元带进位运算实验的解密与实战

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《机组 | 模块单元实验》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 ​ 目录 &#x1f33a;一、 实验目…

MySQL锁机制与优化实践

数据库乐观和悲观锁 乐观锁 比如在数据库中设置一个版本字段&#xff0c;每操作一次&#xff0c;都会将这行对应的版本号1&#xff0c;这样下次更新都会拿到最新的版本号更新&#xff0c;如果一个事务拿到了版本号但是更新前其他人已经将版本号升级了&#xff0c;那么当前事务…

消除噪音:Chain-of-Note (CoN) 强大的方法为您的 RAG 管道提供强大动力

论文地址&#xff1a;https://arxiv.org/abs/2311.09210 英文原文地址&#xff1a;https://praveengovindaraj.com/cutting-through-the-noise-chain-of-notes-con-robust-approach-to-super-power-your-rag-pipelines-0df5f1ce7952 在快速发展的人工智能和机器学习领域&#x…

HackTheBox - Medium - Linux - BackendTwo

BackendTwo BackendTwo在脆弱的web api上通过任意文件读取、热重载的uvicorn从而访问目标&#xff0c;之后再通过猜单词小游戏获得root 外部信息收集 端口扫描 循例nmap Web枚举 feroxbuster扫目录 /api/v1列举了两个节点 /api/v1/user/1 扫user可以继续发现login和singup 注…