基于javaConfig的无配置文件的SSM项目整合
文章目录
pom.xml
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>com.fu</groupId>
<artifactId>ssm-annotation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<spring.version>5.1.5.RELEASE</spring.version>
<mybatis.version>3.4.6</mybatis.version>
<!-- log4j日志文件管理包版本 -->
<slf4j.version>1.7.7</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<tomcat.version>8.5.46</tomcat.version>
</properties>
<dependencies>
<!-- JSON -->
<!-- fastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jstl的jar -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Spring相关的jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</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-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- pageHelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
<!-- mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<!-- 参数验证 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- Tomcat -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- 日志相关 -->
<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>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<!--需要设置打包的文件 特别是非java文件-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
<plugins>
<!-- maven中用到的编译插件,指定编译时使用的jdk的版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerVersion>1.8</compilerVersion>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
AppConfig.java (spring)
package com.fu.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.*;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.Reader;
import java.util.Properties;
/**
* spring 配置类
*/
@Configuration
@ComponentScan(value = "com.fu", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})
@MapperScan("com.fu.dao")
@EnableAspectJAutoProxy // 开启 AOP 通知功能
@EnableTransactionManagement // 开启事务管理功能;
public class AppConfig {
// 配置数据源
@Bean
public DataSource dataSource() {
Properties properties = new Properties();
try {
Reader reader = Resources.getResourceAsReader("db.properties");
properties.load(reader);
} catch (IOException e) {
e.printStackTrace();
}
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.configFromPropety(properties);
return druidDataSource;
}
// 配置和MyBatis的整合
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sqlSessionFactory = null;
// 数据源
sqlSessionFactoryBean.setDataSource(dataSource());
// 批量起别名
sqlSessionFactoryBean.setTypeAliasesPackage("com.fu.bean");
PathMatchingResourcePatternResolver pr = new PathMatchingResourcePatternResolver();
try {
// mapper映射文件
sqlSessionFactoryBean.setMapperLocations(pr.getResources("classpath:/mapper/*.xml"));
sqlSessionFactory = sqlSessionFactoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return sqlSessionFactory;
}
// 配置事务管理器
@Bean("transactionManager")
public PlatformTransactionManager transactionManager() {
PlatformTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource());
return dataSourceTransactionManager;
}
}
WebmvcConfig.java (springmvc)
package com.fu.config;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
/**
* springMVC 配置类
*/
@ComponentScan(value = "com.fu.controller")
@EnableWebMvc // 让SpringMVC的注解和配置生效, 等同于<mvc:annotation-driven />
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 配置视图解析器
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/", ".html");
}
/**
* 配置默认Servlet处理(不拦截静态资源)
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 配置JSON 解析器, 使用fastJson
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 字符串解析器,如果不配置这个字符串解析器,只配置json解析器,当返回值为字符串时,字符串会被转义
converters.add(new StringHttpMessageConverter());
// 不加以下内容会抛出异常 IllegalArgumentException:内容类型不能包含通配符类型“ * ”
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
supportedMediaTypes.add(MediaType.APPLICATION_PDF);
supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XML);
supportedMediaTypes.add(MediaType.IMAGE_GIF);
supportedMediaTypes.add(MediaType.IMAGE_JPEG);
supportedMediaTypes.add(MediaType.IMAGE_PNG);
supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
supportedMediaTypes.add(MediaType.TEXT_XML);
fastConverter.setSupportedMediaTypes(supportedMediaTypes);
converters.add(fastConverter);
}
/**
* 配置文件上传解析器
*/
@Bean("multipartResolver") // name 必须是multipartResolver,否则不生效
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
// 最大上传大小为 10m
commonsMultipartResolver.setMaxUploadSize(1024 * 1024 * 10);
// 此为阈值,低于此值,则保存在内存中,如高于此值,则生成硬盘上的临时文件
// commonsMultipartResolver.setMaxInMemorySize();
commonsMultipartResolver.setDefaultEncoding("utf-8");
return commonsMultipartResolver;
}
/**
* 配置 JSR303(Bean Validation) 验证器
*/
@Bean("messageSource")
public MessageSource messageSource() {
ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
resourceBundleMessageSource.setUseCodeAsDefaultMessage(false);
resourceBundleMessageSource.setDefaultEncoding("UTF-8");
resourceBundleMessageSource.setBasenames("ValidationMessages");
return resourceBundleMessageSource;
}
@Bean("validator")
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
localValidatorFactoryBean.setValidationMessageSource(messageSource());
return localValidatorFactoryBean;
}
/**
* 方法级别的单个参数验证开启
*/
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
RootConfig.java (WEB)
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
/**
* web根容器配置类
* tomcat启动的时候会自动加载实现了 WebApplicationInitializer 接口的类,运行 onStartup 方法
*/
public class RootConfig implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
// 向web容器中注册 spring 的配置和springMVC的配置
ac.register(AppConfig.class, WebmvcConfig.class);
// 配置dispatcherServlet,添加web容器的配置
DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcherServlet", dispatcherServlet);
// 容器启动的时候加载该servlet
servlet.setLoadOnStartup(1);
// 配置dispatcherServlet的映射路径
servlet.addMapping("/");
}
}
Main (启动)
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
/**
* Main线程启动类
*/
public class Main {
public static void main(String[] args) {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
// contextPath:启动时路径资源名。
// docBase:webapp的目录。目前只能写绝对路径,解决方法暂未找到
tomcat.addWebapp("/ssm", "H:\\workspace\\ssm-annotation\\src\\main\\webapp");
try {
// 启动
tomcat.start();
// 线程阻塞,不阻塞的话,tomcat启动完成之后会关闭
tomcat.getServer().await();
} catch (LifecycleException e) {
e.printStackTrace();
}
}
}
AOP 通知
package com.fu.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 通知类
* @Aspect 告诉Spring当前类是一个切面类
*/
@Aspect
@Component
public class LogAspectsConfig {
@Pointcut("execution(* com.fu.service..*(..))")
public void pointCut() {}
/*
* JoinPoint joinPoint 连接点
* JoinPoint 一定要出现在参数表的第一位,否则spring识别不出来,会抛出异常
*/
@Before("pointCut()")
public void logBefore(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("logBefore..."+ joinPoint.getSignature().getName() +"方法运行...参数为:" + Arrays.toString(args));
}
@After("pointCut()")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("logAfter..."+methodName+"方法运行结束...");
}
/*
value = "pointCut()" 切点
returning = "result" 返回方法运行的结果,使用一个参数(result)接收,参数和方法参数名对应
*/
@AfterReturning(value = "pointCut()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("logAfterReturning..."+ methodName +"正常返回,返回值是:" + result);
}
@AfterThrowing(value = "pointCut()", throwing = "throwable")
public void logAfterThrowing(JoinPoint joinPoint, Throwable throwable) {
String methodName = joinPoint.getSignature().getName();
System.out.println("logAfterThrowing..."+ methodName +"方法出现异常,异常信息为:" + throwable);
}
/*
环绕通知和异常通知同时使用,如果使用 try{}catch(){} 方式捕获异常,
则需要把异常信息重新抛出,否则异常通知不生效(捕获不到异常)
*/
@Around("pointCut()")
public Object logAround(ProceedingJoinPoint point) throws Throwable {
Object result = null;
System.out.println("logAround...Before...");
result = point.proceed();
System.out.println("logAround...After...result = " + result);
return result;
}
}
AOP 切面方式配置事务
package com.fu.config;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* AOP 切面方式配置事务
*/
@Aspect
@Component
public class TransactionAdviceConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.fu.service..*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
// 配置事务拦截器
@Bean
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionManager(transactionManager);
// 设置事务属性
DefaultTransactionAttribute tx_REQUIRED = new DefaultTransactionAttribute();
tx_REQUIRED.setIsolationLevel(-1); // 事务隔离级别:默认为 ISOLATION_DEFAULT(-1)
tx_REQUIRED.setPropagationBehavior(0); // 事务传播行为:默认为 PROPAGATION_REQUIRED(0)
DefaultTransactionAttribute tx_REQUIRED_READONLY = new DefaultTransactionAttribute();
tx_REQUIRED_READONLY.setReadOnly(true); // 是否只读,默认为 false
// 设置 NameMatchTransactionAttributeSource 名称匹配事务属性来源
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("add*", tx_REQUIRED);
source.addTransactionalMethod("save*", tx_REQUIRED);
source.addTransactionalMethod("insert*", tx_REQUIRED);
source.addTransactionalMethod("delete*", tx_REQUIRED);
source.addTransactionalMethod("update*", tx_REQUIRED);
source.addTransactionalMethod("exec*", tx_REQUIRED);
source.addTransactionalMethod("set*", tx_REQUIRED);
source.addTransactionalMethod("get*", tx_REQUIRED_READONLY);
source.addTransactionalMethod("query*", tx_REQUIRED_READONLY);
source.addTransactionalMethod("find*", tx_REQUIRED_READONLY);
source.addTransactionalMethod("list*", tx_REQUIRED_READONLY);
source.addTransactionalMethod("count*", tx_REQUIRED_READONLY);
source.addTransactionalMethod("is*", tx_REQUIRED_READONLY);
// 设置 TransactionInterceptor 事务拦截器
transactionInterceptor.setTransactionAttributeSource(source);
return transactionInterceptor;
}
// 设置切入点
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor());
}
}
JSR 303 验证异常解析器
package com.fu.common;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Iterator;
/**
* 配置常用异常处理器
*/
@ControllerAdvice
@Component
public class CommonExceptionHandler {
/**
* 处理 JSR303 校验不通过异常
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public JsonResult constraintViolationException(ConstraintViolationException exception) {
// 验证不通过的信息
Iterator<ConstraintViolation<?>> iterator = exception.getConstraintViolations().iterator();
StringBuilder str = new StringBuilder();
while (iterator.hasNext()) {
str.append(iterator.next().getMessage());
str.append("\n");
}
System.out.println(str);
return new JsonResult(100, str.toString());
}
}
全局异常解析器
package com.fu.common;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 全局异常处理器
*/
@Component
public class GlobalExceptionHandler implements HandlerExceptionResolver {
private Logger logger = Logger.getLogger(getClass());
/**
* 处理所有不可知的异常,全局异常处理器,跳转到错误页面。所有未处理的异常,都会被处理。
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o, Exception e) {
logger.error("Catch-exception");
e.printStackTrace();
return new ModelAndView("500");
}
}