使用纯Java配置SSM框架实现基本的增删改查(不使用spring XML)

前言

本文不使用spring XML,而是采用Java配置SSM框架的形式实现了基本的增删改查。

本文中的源码继承自https://www.cnblogs.com/hanzx/p/10016468.html中的程序,删除掉了webapp文件夹,里面的模板全部转移到resources下,其余文件均已删除。

核心框架已升级。spring系列已升级使用5.0.1,mybatis使用3.4.5,mybatis-spring使用1.3.1。

 

名词解释

SSM框架:springMVC、spring、mybatis

thymeleaf:一个与Velocity、FreeMarker类似的模板引擎

jquery:一个快速、简洁的JavaScript框架

 

程序结构

 

 

程序源码

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.hanzx</groupId>
  <artifactId>webssmwithoutxml</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>webssmwithoutxml Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <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>
    <spring.version>5.0.1.RELEASE</spring.version>
    <slf4j.version>1.6.6</slf4j.version>
    <log4j.version>1.2.12</log4j.version>
    <mysql.version>5.1.35</mysql.version>
    <jackson.version>2.9.2</jackson.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- 添加Spring依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</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-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-tx</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-web</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--spring单元测试依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- spring webmvc相关jar -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!-- mysql驱动包 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql.version}</version>
    </dependency>

    <!-- alibaba data source 相关jar包-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>0.2.23</version>
    </dependency>

    <!-- alibaba fastjson 格式化对 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.1.41</version>
    </dependency>

    <!-- logback start -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>${log4j.version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${slf4j.version}</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.2</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.1.2</version>
    </dependency>
    <dependency>
      <groupId>org.logback-extensions</groupId>
      <artifactId>logback-ext-spring</artifactId>
      <version>0.1.1</version>
    </dependency>

    <!--mybatis依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>

    <!-- mybatis/spring包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!-- 添加servlet3.0核心包 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.2-b01</version>
    </dependency>
    <!-- jstl -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!--thymeleaf-->
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring5</artifactId>
      <version>3.0.9.RELEASE</version>
    </dependency>


    <!-- json -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>webssmwithoutxml</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

 

package-info.java(使用new-file创建的,用java class无法创建)

/**package级别的注解。。。不配置的话,WebInitializer里的getServletMappings方法报黄*/
@NonNullApi
package org.hanzx.config;

import org.springframework.lang.NonNullApi;

springConfig.java

package org.hanzx.config;

import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;

/**spring配置类
 * 注解扫描基础package,排除controller
 */
@Configuration
@ComponentScan(basePackages = {"org.hanzx"},
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})})
@Import(value = SpringMybatisConfig.class)
public class SpringConfig {


}

SpringMvcConfig.java

package org.hanzx.config;

import org.hanzx.interceptors.CORSInterceptor;
import org.springframework.context.annotation.*;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
import org.springframework.web.servlet.config.annotation.*;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

import java.util.Properties;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.hanzx.controller"}, useDefaultFilters = false,
    includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})})
public class SpringMvcConfig implements WebMvcConfigurer {

    @Bean
    public ContentNegotiationManagerFactoryBean contentNegotiationManagerFactoryBean(){
        ContentNegotiationManagerFactoryBean contentNegotiationManagerFactoryBean = new ContentNegotiationManagerFactoryBean();
        //扩展名至mimeType的映射,即 /userEntity.json => application/json
        contentNegotiationManagerFactoryBean.setFavorPathExtension(true);
        //用于开启 /userinfo/123?format=json 的支持
        contentNegotiationManagerFactoryBean.setFavorParameter(true);
        contentNegotiationManagerFactoryBean.setParameterName("format");
        //是否忽略Accept Header
        contentNegotiationManagerFactoryBean.setIgnoreAcceptHeader(false);
        //扩展名到MIME的映射;favorPathExtension, favorParameter是true时起作用
        Properties properties = new Properties();
        properties.setProperty("json", "application/json");
        properties.setProperty("xml", "application/xml");
        properties.setProperty("html", "text/html");
        contentNegotiationManagerFactoryBean.setMediaTypes(properties);
        //默认的content type
        contentNegotiationManagerFactoryBean.setDefaultContentType(MediaType.TEXT_HTML);
        return contentNegotiationManagerFactoryBean;
    }

//    这个是旧版用的,新版不要它
//    /**当在web.xml 中   DispatcherServlet使用 <url-pattern>/</url-pattern> 映射时,能映射静态资源*/
//    @Override
//    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
//
//    }

    /**静态资源映射*/
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }

    /**对模型视图添加前后缀及其他*/
    @Bean
    public SpringResourceTemplateResolver springResourceTemplateResolver(){
        SpringResourceTemplateResolver springResourceTemplateResolver = new SpringResourceTemplateResolver();
        springResourceTemplateResolver.setPrefix("/templates/");
        springResourceTemplateResolver.setSuffix(".html");
        springResourceTemplateResolver.setCharacterEncoding("UTF-8");
        springResourceTemplateResolver.setOrder(1);
        springResourceTemplateResolver.setTemplateMode("HTML5");
        springResourceTemplateResolver.setCacheable(false);
        return springResourceTemplateResolver;
    }

    @Bean
    public SpringTemplateEngine springTemplateEngine(){
        SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
        springTemplateEngine.setTemplateResolver(springResourceTemplateResolver());
        return springTemplateEngine;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(){
        ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
        thymeleafViewResolver.setTemplateEngine(springTemplateEngine());
        thymeleafViewResolver.setCharacterEncoding("UTF-8");
        return thymeleafViewResolver;
    }

    /**拦截器 跨域拦截器*/
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CORSInterceptor());
    }


    /**
     * 默认首页的设置,当输入域名是可以自动跳转到默认指定的网页
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }
}

SpringMybatisConfig.java

package org.hanzx.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.io.IOException;
import java.sql.SQLException;


@Configuration
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
@MapperScan("org.hanzx.dao")//扫描mapper
public class SpringMybatisConfig {
    @Value("${jdbc_driverClassName}")
    private String driverClassName;
    @Value("${jdbc_url}")
    private String url;
    @Value("${jdbc_username}")
    private String userName;
    @Value("${jdbc_password}")
    private String password;
    @Value("${initialSize}")
    private Integer initialSize;
    @Value("${minIdle}")
    private Integer minIdle;
    @Value("${maxActive}")
    private Integer maxActive;
    @Value("${maxWait}")
    private Long maxWait;
    @Value("${timeBetweenEvictionRunsMillis}")
    private Long timeBetweenEvictionRunsMillis;
    @Value("${minEvictableIdleTimeMillis}")
    private Long minEvictableIdleTimeMillis;
    @Value("${validationQuery}")
    private String validationQuery;
    @Value("${testWhileIdle}")
    private Boolean testWhileIdle;
    @Value("${testOnBorrow}")
    private Boolean testOnBorrow;
    @Value("${testOnReturn}")
    private Boolean testOnReturn;
    @Value("${poolPreparedStatements}")
    private Boolean poolPreparedStatements;
    @Value("${maxPoolPreparedStatementPerConnectionSize}")
    private Integer maxPoolPreparedStatementPerConnectionSize;
    @Value("${filters}")
    private String filters;

//    这个无须使用,直接配@PropertySource注解就可以了
//    /** 这个bean必须配置而且必须是静态方法,如果不配置就不能进行@Value的属性注入*/
//    @Bean
//    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
//        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
//        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
//        configurer.setLocation(resourcePatternResolver.getResource("classpath:jdbc.properties"));
//        return configurer;
//    }

//    这个旧了,不再使用了,spring 3.1以后推荐使用PropertySourcesPlaceholderConfigurer
//    @Deprecated
//    @Bean
//    public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() throws IOException {
//        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
//        PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
//        configurer.setLocation(resourcePatternResolver.getResource("classpath:jdbc.properties"));
//        return configurer;
//    }

    /**配置数据源 ,使用的alibba的数据库*/
    @Bean(initMethod = "init", destroyMethod = "close")
    public DruidDataSource dataSource() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(userName);
        druidDataSource.setPassword(password);
        druidDataSource.setInitialSize(initialSize);
        druidDataSource.setMinIdle(minIdle);
        druidDataSource.setMaxActive(maxActive);
        druidDataSource.setMaxWait(maxWait);
        druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        druidDataSource.setValidationQuery(validationQuery);
        druidDataSource.setTestWhileIdle(testWhileIdle);
        druidDataSource.setTestOnBorrow(testOnBorrow);
        druidDataSource.setTestOnReturn(testOnReturn);
        druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        druidDataSource.setFilters(filters);
        return druidDataSource;
    }

    /** spring和MyBatis完美整合,不需要mybatis的配置映射文件 */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws SQLException, IOException {
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:mapper/*.xml"));
        return sqlSessionFactoryBean;
    }

    //不能使用这个,这东西先于properties加载,会导致properties文件读不出数据,改用@MapperScan扫描dao
//    /**DAO接口所在包名,Spring会自动查找其下的类 ,自动扫描了所有的XxxxMapper.xml对应的mapper接口文件,
//     * 只要Mapper接口类和Mapper映射文件对应起来就可以了*/
//    @Bean
//    public MapperScannerConfigurer mapperScannerConfigurer(){
//        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
//        mapperScannerConfigurer.setBasePackage("org.hanzx.dao");
//        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
//        return mapperScannerConfigurer;
//    }

    /**(事务管理)transaction manager, use JtaTransactionManager for global tx 配置事务管理器*/
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager() throws SQLException {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource());
        return dataSourceTransactionManager;
    }
}

WebInitializer.java

package org.hanzx.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * 在Servlet3.0以上的环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果发现则用它来配置 * Servlet容器,Spring提供了这个接口的实现名为SpringServletContainerInitializer,这个类反过来又会查找实现了 * WebApplicationInitializer的类并把配置任务交给它们来完成,AbstractAnnotationConfigDispatcherServletInitializer的祖先类已 * 对该接口进行了实现
 */
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    private final static Logger LOG = LoggerFactory.getLogger(WebInitializer.class);

/**     * 该方法用于配置ContextLoaderListener创建的应用上下文的bean,相当于web.xml配置中的
 * * <listener>org.springframework.web.ContextLoaderListener</listener> 差异:
 * * 注解配置需要添加的是配置类<br>
 * * 文件配置ContextLoaderListener在创建时自动查找WEB-INF下的applicationContext.xml文件,
 * 当文件不止1个时需通过设置     * 上下文参数(context-param)配置contextConfigLocation的值
 * *      * @return 带有@Configuration注解的类(这些类将会用来配置ContextLoaderListener创建的应用上下文的bean)
 */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        LOG.info("------root配置类初始化------");
        return new Class<?>[]{SpringConfig.class};
    }

    /**     * 该方法用于配置DispatcherServlet所需bean,配置类一般用于生成控制层的bean(因Controller中一般包含对参数的设置及数据的返回)     * 相当于web.xml对Spring     * MVC的配置…<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>…<br>     * 配置类如WebConfig.class相当于DispatcherServlet中contetConfigLocation参数对应的配置文件     *      * @return 带有@Configuration注解的类(这些类将会用来配置DispatcherServlet应用上下文中的bean)     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        LOG.info("------web配置类初始化------");
        return new Class<?>[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        LOG.info("------映射根路径初始化------");
        return new String[]{"/"};// 请求路径映射,将路径映射到DispatcherServlet上,这里可以配置成/* 拦截所有
    }

}

UserController.java

package org.hanzx.controller;

import org.hanzx.model.UserModel;
import org.hanzx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {

    private final UserService userService;
    private String prefix = "user/";

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }



//    @RequestMapping(value="/getAllUser")
//    @ResponseBody
//    public List<UserModel> getAllUser(){
//        return userService.getAllUser();
//    }
//
//    @RequestMapping(value="/addUser")
//    @ResponseBody
//    public boolean addUser(UserModel userModel){
//        userService.addUser(userModel);
//        return true;
//    }
//
//    @RequestMapping(value="/updateUser")
//    @ResponseBody
//    public boolean updateUser(UserModel userModel){
//        userService.updateUser(userModel);
//        return true;
//    }
//
//    @RequestMapping(value="/deleteUser")
//    @ResponseBody
//    public boolean deleteUser(@RequestParam(value = "ids[]") Integer[] ids){
//        userService.deleteUser(ids);
//        return true;
//    }


//    @RequestMapping(value="/getUserListForm")
//    public String getUserListForm(){
//        return prefix + "user_list";
//    }

    @RequestMapping(value="/getAllUser")
    public String getAllUser(ModelMap modelMap){
        modelMap.put("userModelList", userService.getAllUser());
        return prefix + "user_list";
    }

    @RequestMapping(value="/getUserDetailForm")
    public String getUserDetailForm(ModelMap modelMap, Integer id){
        if (id != null){
            modelMap.put("userModel", userService.getUserById(id));
        }
        return prefix + "user_detail";
    }

    @RequestMapping(value="/addUser")
    public String addUser(UserModel userModel){
        userService.addUser(userModel);
        return "redirect:getAllUser";
    }

    @RequestMapping(value="/updateUser")
    public String updateUser(UserModel userModel){
        userService.updateUser(userModel);
        return "redirect:getAllUser";
    }

    @RequestMapping(value="/deleteUser")
    @ResponseBody
    public boolean deleteUser(@RequestParam(value = "ids[]") Integer[] ids){
        userService.deleteUser(ids);
        return true;
    }


}

UserDao.java

package org.hanzx.dao;


import org.hanzx.entity.UserEntity;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserDao {

    List<UserEntity> getAllUser();

    void addUser(UserEntity userEntity);

    UserEntity getUserById(Integer id);

    void updateUser(UserEntity userEntity);

    void deleteUserById(Integer id);
}

UserEntity.java

package org.hanzx.entity;



public class UserEntity {

    private Integer id;

    private String name;

    private Integer age;

    private String password;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

CORSInterceptor.java

package org.hanzx.interceptors;


import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CORSInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截请求: " + request.getServletPath());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "0");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("XDomainRequestAllowed", "1");
        return true;
    }
}

UserModel.java

package org.hanzx.model;



public class UserModel {

    private Integer id;

    private String name;

    private Integer age;

    private String password;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

UserServiceImpl.java

package org.hanzx.service.impl;

import org.hanzx.dao.UserDao;
import org.hanzx.entity.UserEntity;
import org.hanzx.model.UserModel;
import org.hanzx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserServiceImpl implements UserService{

    private final UserDao userDao;

    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public List<UserModel> getAllUser() {
        List<UserEntity> userEntityList = userDao.getAllUser();
        List<UserModel> userModelList = new ArrayList<>();
        for (UserEntity userEntity : userEntityList){
            UserModel userModel = new UserModel();
            userModel.setName(userEntity.getName());
            userModel.setId(userEntity.getId());
            userModel.setAge(userEntity.getAge());
            userModelList.add(userModel);
        }
        return userModelList;
    }

    @Override
    public void addUser(UserModel userModel) {
        UserEntity userEntity = new UserEntity();
        userEntity.setName(userModel.getName());
        userEntity.setAge(userModel.getAge());
        userEntity.setPassword(userModel.getPassword());
        userDao.addUser(userEntity);
    }

    @Override
    public UserModel getUserById(Integer id) {
        UserEntity userEntity = userDao.getUserById(id);
        UserModel userModel = new UserModel();
        userModel.setAge(userEntity.getAge());
        userModel.setId(userEntity.getId());
        userModel.setName(userEntity.getName());
        userModel.setPassword(userEntity.getPassword());
        return userModel;
    }

    @Override
    public void updateUser(UserModel userModel) {
        UserEntity userEntity = userDao.getUserById(userModel.getId());
        userEntity.setPassword(userModel.getPassword());
        userEntity.setAge(userModel.getAge());
        userEntity.setName(userModel.getName());
        userDao.updateUser(userEntity);
    }

    @Override
    public void deleteUser(Integer[] ids) {
        for (Integer id : ids){
            userDao.deleteUserById(id);
        }
    }
}

UserService.java

package org.hanzx.service;


import org.hanzx.model.UserModel;

import java.util.List;

public interface UserService {

    List<UserModel> getAllUser();

    void addUser(UserModel userModel);

    UserModel getUserById(Integer id);

    void updateUser(UserModel userModel);

    void deleteUser(Integer[] ids);
}

UserMapper.xml

<?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="org.hanzx.dao.UserDao">
    <resultMap id="BaseResultMap" type="org.hanzx.entity.UserEntity" >
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="password" property="password" jdbcType="VARCHAR" />
        <result column="age" property="age" jdbcType="INTEGER" />
    </resultMap>
    <select id="getAllUser" resultMap="BaseResultMap" >
      SELECT * FROM user;
    </select>

    <insert id="addUser">
        INSERT USER VALUES (null, #{name}, #{age}, #{password});
    </insert>

    <select id="getUserById" resultMap="BaseResultMap">
        SELECT * FROM user WHERE user.id = #{id};
    </select>

    <update id="updateUser">
        UPDATE user SET name = #{name}, age = #{age}, password = #{password} WHERE id = #{id};
    </update>

    <delete id="deleteUserById">
        DELETE FROM user where id = #{id};
    </delete>

</mapper>

user_detail.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div th:if="${userModel} eq null">
        <form th:action="addUser" th:method="post">
    </div>
    <div th:if="${userModel} ne null">
        <form th:action="updateUser" th:method="post">
    </div>
        <table>
            <tr>
                <th>用户名</th>
                <td><input th:type="text" th:name="name" th:value="${userModel == null? '' : userModel.name}" th:title="请输入用户名"/></td>
            </tr>
            <tr>
                <th>密码</th>
                <td><input th:type="password" th:name="password" th:title="请输入密码"/></td>
            </tr>
            <tr>
                <th>年龄</th>
                <td><input th:type="number" th:name="age" th:value="${userModel == null? '' : userModel.age}" th:title="请输入年龄"/></td>
            </tr>
            <tr><td th:colspan="2" ><input th:type="submit" th:value="提交" /></td></tr>
        </table>
        <input th:type="hidden" th:name="id" th:value="${userModel == null? null : userModel.id}" />
    </form>
</body>
</html>

user_list.html

<!DOCTYPE html>
<html lang="cn" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>userEntityList</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js" ></script>
    <script type="text/javascript">
        $(function () {
            //全选
            $("#selectAll").click(function () {
                if (this.checked) {
                    $("input[name=deleteId]").prop("checked", true);
                } else {
                    $("input[name=deleteId]").prop("checked", false);
                }
            });

            $("input[name=deleteId]").click(function () {
                var allChecked = true;
                $("input[name=deleteId]").each(function(){
                    if(!$(this).prop("checked")){
                        allChecked = false;
                    }
                });
                if(allChecked){
                    $("#selectAll").prop("checked",true);
                } else {
                    $("#selectAll").prop("checked",false);
                }
            });

            //删除用户
            $("#delete").click(function () {
                var ids = [];
                $("input[name=deleteId]:checked").each(function(index){
                    ids[index] = $(this).val();
                });
                if (ids.length === 0){
                    alert("没有选中的选项");
                    return false;
                }
                $.ajax({
                    url : "deleteUser",
                    data: {"ids": ids},
                    cache : false,
                    async : false,
                    type : "GET",
                    success:function(data){
                        if (data === true){
                            window.location.reload();
                        }
                    }
                });
            });

        });

    </script>
</head>
<body>
    <a th:href="getUserDetailForm">添加</a>
    <a th:id="delete" href="#" >删除</a>
    <table>
        <tr>
            <th><input th:type="checkbox" th:id="selectAll" title="点击全选/取消"/></th>
            <th>用户名</th>
            <th>年龄</th>
            <th>操作</th>
        </tr>
        <tr th:each="userModel : ${userModelList}">
            <td><input th:type="checkbox" th:value="${userModel.id}" th:name="deleteId"/></td>
            <td th:text="${userModel.name}">abc</td>
            <td th:text="${userModel.age}">15</td>
            <td><a th:href="'getUserDetailForm?id=' + ${userModel.id}">修改</a></td>
        </tr>
    </table>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
index
</body>
</html>

jdbc.properties

jdbc_driverClassName=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/web_test?useUnicode=true&characterEncoding=utf8
jdbc_username=root
jdbc_password=root
#配置初始化大小、最小、最大
initialSize=10
minIdle=10
maxActive=50
#配置获取连接等待超时的时间
maxWait=60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 'x'
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
#打开PSCache,并且指定每个连接上PSCache的大小  如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。
poolPreparedStatements=false
maxPoolPreparedStatementPerConnectionSize=20
#配置监控统计拦截的filters
filters=wall,stat

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 尽量别用绝对路径,如果带参数不同容器路径解释可能不同,以下配置参数在pom.xml里 -->
    <property name="log.root.level" value="${log.root.level}" /> <!-- 日志级别 -->
    <property name="log.other.level" value="${log.other.level}" /> <!-- 其他日志级别 -->
    <property name="log.base" value="${log.base}" /> <!-- 日志路径,这里是相对路径,web项目eclipse下会输出到eclipse的安装目录下,如果部署到linux上的tomcat下,会输出到tomcat/bin目录 下 -->
    <property name="log.moduleName" value="${log.moduleName}" />  <!-- 模块名称, 影响日志配置名,日志文件名 -->
    <property name="log.max.size" value="100MB" /> <!-- 日志文件大小,超过这个大小将被压缩 -->

    <!--控制台输出 -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method\(\):%L -%msg%n</Pattern>
        </encoder>
    </appender>

    <!-- 用来保存输出所有级别的日志 -->
    <appender name="file.all" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.base}/${log.moduleName}.log</File><!-- 设置日志不超过${log.max.size}时的保存路径,注意如果
            是web项目会保存到Tomcat的bin目录 下 -->
        <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.base}/archive/${log.moduleName}_all_%d{yyyy-MM-dd}.%i.log.zip
            </FileNamePattern>
            <!-- 文件输出日志 (文件大小策略进行文件输出,超过指定大小对文件备份) -->
            <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${log.max.size}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出的文件的格式 -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method\(\):%L -%msg%n</pattern>
        </layout>
    </appender>

    <!-- 这也是用来保存输出所有级别的日志 -->
    <appender name="file.all.other" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.base}/${log.moduleName}_other.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.base}/archive/${log.moduleName}_other_%d{yyyy-MM-dd}.%i.log.zip
            </FileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${log.max.size}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{56}.%method\(\):%L -%msg%n</pattern>
        </layout>
    </appender>

    <!-- 只用保存输出error级别的日志 -->
    <appender name="file.error"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.base}/${log.moduleName}_err.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.base}/archive/${log.moduleName}_err_%d{yyyy-MM-dd}.%i.log.zip
            </FileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${log.max.size}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{56}.%method\(\):%L - %msg%n</pattern>
        </layout>
        <!-- 下面为配置只输出error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
    <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
    <!-- 添加附加的appender,最多只能添加一个 -->
    <appender name="file.async" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>256</queueSize>
        <includeCallerData>true</includeCallerData>
        <appender-ref ref="file.all" />
    </appender>

    <appender name="file.async.other" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>256</queueSize>
        <includeCallerData>true</includeCallerData>
        <appender-ref ref="file.all.other" />
    </appender>

    <!-- 为某个包下的所有类的指定Appender 这里也可以指定类名称例如:com.aa.bb.ClassName -->
    <logger name="com.lin" additivity="false">
        <level value="${log.root.level}" />
        <appender-ref ref="stdout" />
        <appender-ref ref="file.async" /><!-- 即com.lin包下级别为 ${log.root.level}的才会使用file.async来打印 -->
        <appender-ref ref="file.error" />
    </logger>

    <!-- root将级别为${log.root.level}及大于${log.root.level}的日志信息交给已经配置好的名为“Console”的appender处理,“Console”appender将信息打印到Console,其它同理 -->
    <root level="${log.root.level}">
        <appender-ref ref="stdout" /> <!--  标识这个appender将会添加到这个logger -->
        <appender-ref ref="file.async.other" />
        <appender-ref ref="file.error" />
    </root>
</configuration>

 

效果图

 

存在的问题

1、MapperScannerConfigurer不能使用。因为这东西会先于PropertySourcesPlaceholderConfigurer加载,并调用datasource,导致jdbc.properties里的数据读不到。

咱已经试过了将PropertySourcesPlaceholderConfigurer的bean加载方法改成静态,然而没有用。打过断点,PropertySourcesPlaceholderConfigurer的bean确实先于MapperScannerConfigurer加载,然而还是读不出properties里的数据。

咱也试过MapperScannerConfigurer里配置SqlSessionFactoryBeanName取代配置SqlSessionFactory(这个已经也被划了,旧了过期了),也没有用。

就是读不出properties。天知道哪出了问题,只好暂且先弃用了。改用@PropertySource("classpath:jdbc.properties")注解加载jdbc.properties,使用@MapperScan("org.hanzx.dao")扫描dao。

2、把所有html模板文件迁移进resources/templates里以后,删除掉webapp文件夹以后,还需要在File - project structure - facets - web里面将Web resource directory改为项目的resources下才能正确读取到模板文件。

然而问题在于,reimport了pom.xml以后此项配置就又恢复原状了,目前尚不知道怎么改pom.xml。

 

还望各路高手赐教…

posted on 2019-01-23 15:54  hanzx0313  阅读(489)  评论(0编辑  收藏  举报

导航