文章目录
说明
本文主要是通过注解方式搭建SpringMVC架构,现在通过注解方式搭建框架更加常见以及便捷,文中如果有不妥之处望各位能够批评指正,大家共同进步。
码字不易,转载请注明出处。需要源码请自行下载:https://gitee.com/leo825/spring-framework-learning-example.git
1、工程搭建
可以参考《SpringMVC学习(一)——快速搭建SpringMVC开发环境(非注解方式)》搭建一个非注解型的SpringMVC,注解方式就是在非注解方式的基础之上做的优化。本文也是在这个工程的基础之上做的修改。
2、注解配置
在开启注解的时候遇到几个注解配置:
<context:annotation-config/>
<context:component-scan/>
<mvc:annotation-driven/>
先说明一下这几个注解的定义,通过他们的定义可以理解他们的用途
2.1、context:annotation-config说明
1、如果想使用@Autowired注解,就必须在Spring容器中声明AutowiredAnnotationBeanPostProcessor
的Bean
2、如果想使用@Resource、@PostConstruct、@PreDestroy等注解,就必须在Spring中声明CommonAnnotationBeanPostProcessor
的Bean
3、如果想使用@PersistenceContext注解,就必须在Spring中声明PersistenceAnnotationBeanPostProcessor
的Bean
4、如果想使用 @Required的注解,就必须在Spring中声明RequiredAnnotationBeanPostProcessor
的Bean
AutowiredAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
通过上面的描述我们知道,使用<context:annotation-config/>配置就是向Spring容器中注册上面几个Bean,并实现@Autowired、@Resource、@PostConstruct、@PreDestroy、@PersistenceContext、@Required等注解的功能。
2.2、context:component-scan配置说明
下面的是官网上对于这个标签的描述:
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository,
@Service, and @Controller stereotypes will be detected.
Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.
大致意思就是说<context:component-scan/>包含<context:annotation-config/>要做的事情,同时额外支持@Component、@Repository、@Service、@Controller注解.并且、<context:component-scan/>扫描base-package并且在applicationcontext中注册扫描的beans。因此,如果配置了<context:component-scan/>就不需要再配置<context:annotation-config/>
2.3、mvc:annotation-driven配置说明
根据mvc开头能看出来,这个配置是是针对SpringMVC的,<mvc:annotation-driven/>配置会向Spring容器中自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是@Controller分发请求所必须的。并且这个配置提供了数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson非常主要)。
注意:在笔者测试过程中发现<mvc:annotation-driven/>配置不是必须的,查了原因这个注解驱动主要是配置RequestMappingHandlerMapping和RequestMappingHandlerAdapter。但是springmvc容器启动是会加载默认的DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter。所以不配置也是不影响项目的启动运行的。但是看源码这个两个默认的实现方法是过时的,因此虽然不影响项目,但是我们一般还是会配置<mvc:annotation-driven/>使用新的代替的方法。
这个标签的具体实现类是:
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
通过阅读类的注释,可以找到这个类主要向Spring容器中注册了以下Bean实例
RequestMappingHandlerMapping
BeanNameUrlHandlerMapping
RequestMappingHandlerAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
这些Bean的作用依次为:
1、前面两个RequestMappingHandlerMapping
、BeanNameUrlHandlerMapping
是HandlerMapping接口的实现类,用来处理请求映射的。
- 第一个是处理@RequestMapping注解的。
- 第二个会将Controller类的名称映射为请求的url。
2、中间三个RequestMappingHandlerAdapter
、HttpRequestHandlerAdapter
、SimpleControllerHandlerAdapter
是用来处理请求的。就是调用Controller的那个方法来处理请求。
- 第一个是处理@Controller注解的处理器,支持自定义方法参数和返回值。
- 第二个处理继承HttpRequestHandler的处理器。
- 第三个处理继承自Controller接口的处理器。
3、后面三个是用来处理异常的解析器(自行查看)。
4、除以上之外,此配置还提供以下支持:
- 支持使用ConversionService实例对表单参数进行类型转换;
- 支持使用@NumberFormatannotation、@DateTimeFormat注解完成数据类型的格式化;
- 支持使用@Valid注解对Java bean实例进行JSR 303验证;
- 支持使用@RequestBody和@ResponseBody注解
3、简单代码实现
首先在myspringmvc-servlet.xml中添加上面介绍的注解配置:
<!-- 配置SpringMVC支持注解,需要放在context:component-scan前面,否则可能会报404-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 定义项目扫描包的路径,并支持注解例如:@Component、@Repository、@Service、@Controller-->
<context:component-scan base-package="com.leo"></context:component-scan>
然后开始编写一个Controller,并且添加@Controller注解
@Controller
public class HelloController{
/**
* 返回一个ModeAndView
* @return
* @throws ServletException
* @throws IOException
*/
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public ModelAndView hello() throws ServletException, IOException {
System.out.println("使用配置实现 hello controller 跳转到 success");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", "恭喜您,测试成功了");
modelAndView.setViewName("success");//跳转到/WEB-INF/views/success.jsp
return modelAndView;
}
/**
* 返回逻辑视图“success”
* @return
* @throws ServletException
* @throws IOException
*/
@RequestMapping(value = "/hello2",method = RequestMethod.GET)
public String hello2() throws ServletException, IOException {
System.out.println("访问了 hello2");
return "success";
}
/**
* 返回一个字符串
* @return
* @throws ServletException
* @throws IOException
*/
@RequestMapping(value = "/hello3",method = RequestMethod.GET)
@ResponseBody
public String hello3() throws ServletException, IOException {
System.out.println("访问了 hello3");
String hello = "你好 SpringMVC";
return hello;
}
}
使用 @Autowired注入UserInfoService
@Controller
public class GetUserInfoController {
@Autowired
UserInfoService userInfoService;
@RequestMapping("/getUserInfoList1")
public ModelAndView getUserInfoList1(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("GetUserInfoController获取用户信息");
ModelAndView modelAndView = new ModelAndView();
//访问数据库
List userInfoList = userInfoService.getUserInfoList();
System.out.println(userInfoList);
modelAndView.addObject("data", userInfoList);
modelAndView.setViewName("success");//跳转到/WEB-INF/views/success.jsp
return modelAndView;
}
}
如果想使用依赖注入的UserInfoService,首先通过@Service注入到Sping中
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
JdbcTemplate jdbcTemplate;
@Override
public void insertUserInfo(UserInfo userInfo) {
jdbcTemplate.execute("INSERT INTO USER_INFO(NAME,GENDER,AGE,REMARKS) VALUES('" + userInfo.getName() + "','" + userInfo.getGender() + "','" + userInfo.getAge() + "','" + userInfo.getRemarks() + "')");
}
@Override
public void deleteUserInfo(Integer id) {
DBUtil.getJdbcTemple().execute("DELETE FROM USER_INFO WHERE ID = " + id);
}
@Override
public void updateUserInfo(Integer id, UserInfo newUserInfo) {
jdbcTemplate.update("UPDATE USER_INFO SET NAME=?, GENDER=?, AGE=? ,REMARKS=? WHERE ID=?", new Object[]{
newUserInfo.getName(),
newUserInfo.getGender(),
newUserInfo.getAge(),
newUserInfo.getRemarks(),
id
});
}
@Override
public List<UserInfo> getUserInfoList() {
List<UserInfo> userInfos = new ArrayList<>();
List<Map<String, Object>> results = jdbcTemplate.queryForList("SELECT * FROM USER_INFO");
for (Map obj : results) {
UserInfo userInfo = new UserInfo();
userInfo.setId((Integer) obj.get("ID"));
userInfo.setName((String) obj.get("NAME"));
userInfo.setGender("0".equals((String) obj.get("GENDER")) ? "女" : "男");
userInfo.setAge((String) obj.get("AGE"));
userInfo.setRemarks((String) obj.get("REMARKS"));
userInfos.add(userInfo);
}
return userInfos;
}
}
4、文件上传下载实现
4.1 文件上传jar包依赖
首先,如果没有添加jar包依赖的在pom.xml中添加依赖
<!-- SpirngMVC支持文件上传的工具包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
4.2 在Spring中添加Bean配置
其次,需要在myspringmvc-servlet.xml配置文件中添加Bean支持
<!-- 使用文件上传下载功能需要注入 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和 jsp 的 pageEncoding 属性一致,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 上传最大限制 1M = 1M * 1024 * 1024 = 1048576 byte-->
<property name="maxUploadSize" value="1048576"></property>
</bean>
4.3 文件上传实现
通过以上的配置值就可以使用MutipartFile直接接收文件了
/**
* 文件上传
*
* @param multipartFil
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(@RequestParam(value = "file") MultipartFile multipartFil, HttpServletRequest request) throws IOException {
if (!multipartFil.isEmpty()) {
//文件标签名
System.out.println(multipartFil.getName());
//上传文件名称
System.out.println(multipartFil.getOriginalFilename());
//文件大小
System.out.println(multipartFil.getSize());
//上传文件的类型
System.out.println(multipartFil.getContentType());
String fileDirStr = request.getServletContext().getRealPath("/uploadFile");
String filename = multipartFil.getOriginalFilename();
System.out.println(fileDirStr);
File fileDir = new File(fileDirStr);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
File file1 = new File(fileDir, filename);
multipartFil.transferTo(file1);
}
return "success";
}
前端的测试代码如下:
<form action="${pageContext.request.contextPath}/upload"
enctype="multipart/form-data"
method="post">
<input type="file" name="file" value="请选择需要上传的文件" /><br>
<input type="submit" value="提交">
</form>
4.4 文件下载实现
文件下载的方式也有很多,这里提供一下三种测试方法:
/**
* 下载文件:
* 通过Spring提供的这种对象,这种下载具有局限性,文件太大会导致内存溢出异常
*
* @param request
* @param filename
* @return
* @throws IOException
*/
@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<byte[]> download(HttpServletRequest request, @RequestParam String filename) throws IOException {
String fileDirStr = request.getServletContext().getRealPath("/uploadFile");
File file = new File(fileDirStr, filename);
byte[] body = FileUtils.readFileToByteArray(file);
//设置下载名称,否则乱码
String downloadFilename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");
HttpHeaders httpHeaders = new HttpHeaders();
//设置文件类型
httpHeaders.add("Content-Disposition", "attchement;filename=" + downloadFilename);
ResponseEntity responseEntity = new ResponseEntity(body, httpHeaders, HttpStatus.OK);
return responseEntity;
}
/**
* 使用字节流直接输出,实现类似上面
*
* @param request
* @param response
* @param filename
*/
@RequestMapping(value = "/download2", method = RequestMethod.GET)
public void download2(HttpServletRequest request, HttpServletResponse response, @RequestParam String filename) throws IOException {
//获取主机文件
String fileDirStr = request.getServletContext().getRealPath("/uploadFile");
File file = new File(fileDirStr, filename);
byte[] outByte = FileUtils.readFileToByteArray(file);
//设置下载名称,否则乱码
String downloadFilename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");
response.setHeader("Content-Disposition", "attchement;filename=" + downloadFilename);
response.getOutputStream().write(outByte);
response.getOutputStream().close();
}
/**
* 普通的输出输出流下载
*
* @param request
* @param response
* @param filename
* @throws IOException
*/
@RequestMapping(value = "/download3", method = RequestMethod.GET)
public void download3(HttpServletRequest request, HttpServletResponse response, @RequestParam String filename) throws IOException {
//获取主机文件
String fileDirStr = request.getServletContext().getRealPath("/uploadFile");
File file = new File(fileDirStr, filename);
InputStream inputStream = new FileInputStream(file);
//设置下载名称,否则乱码
String downloadFilename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");
response.setHeader("Content-Disposition", "attchement;filename=" + downloadFilename);
OutputStream os = response.getOutputStream();
byte[] bf = new byte[2048];
int len;
while ((len = inputStream.read(bf)) > 0) {
os.write(bf, 0, len);
}
os.close();
inputStream.close();
}
5、拦截器配置
5.1 拦截器代码实现
首先,编写两个拦截器继承自HandlerInterceptorAdapter
第一个拦截器:
public class HandlerInterceptor1 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("HandlerInterceptor1 preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor1 postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("HandlerInterceptor1 afterCompletion");
}
}
第二个拦截器:
public class HandlerInterceptor2 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("HandlerInterceptor2 preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor2 postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("HandlerInterceptor2 afterCompletion");
}
}
5.2 拦截器配置实现
编写完上面的拦截器代码之后,需要将Bean实例注入到Spring中
<!-- 拦截器实现 -->
<mvc:interceptors>
<bean class="com.leo.interceptor.HandlerInterceptor1"></bean>
<bean class="com.leo.interceptor.HandlerInterceptor2"></bean>
</mvc:interceptors>
访问:http://localhost:8080/springmvc/hello
执行情况如下日志所示:
HandlerInterceptor1 preHandle
HandlerInterceptor2 preHandle
HelloController.handlerAllException
HandlerInterceptor2 afterCompletion
HandlerInterceptor1 afterCompletion
HandlerInterceptor1 preHandle
HandlerInterceptor2 preHandle
使用配置实现 hello controller 跳转到 success
HandlerInterceptor2 postHandle
HandlerInterceptor1 postHandle
HandlerInterceptor2 afterCompletion
HandlerInterceptor1 afterCompletion
5.3 排除拦截器配置实现
需要在myspringmvc-servlet.xml配置文件中添加如下配置信息:
<!-- 拦截器实现 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截对应 /hello 路径下的所有请求 -->
<mvc:mapping path="/springmvc/*"/>
<!-- 除去 /springmvc/hello 这个请求 -->
<mvc:exclude-mapping path="/springmvc/hello"></mvc:exclude-mapping>
<bean class="com.leo.interceptor.HandlerInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 所有请求 -->
<mvc:mapping path="/**"/>
<bean class="com.leo.interceptor.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
配置后,再访问:http://localhost:8080/springmvc/hello
控制台输出的日志为如下:
HandlerInterceptor2 preHandle
使用配置实现 hello controller 跳转到 success
HandlerInterceptor2 postHandle
HandlerInterceptor2 afterCompletion
想了解过滤器和拦截器区别的可以参考:《SpringMVC中过滤器和拦截器的区别》
6、统一异常配置
@ControllerAdvice 注解修饰可以处理所有的Controller的异常
@ControllerAdvice
public class HandlerException {
@ExceptionHandler
public ModelAndView handlerAllException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("exceptionMsg", e.getMessage());
mv.setViewName("error");
System.out.println("HelloController.handlerAllException");
return mv;
}
@ExceptionHandler(value = {ArithmeticException.class})
public ModelAndView handlerArithmeticException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("exceptionMsg", e.getMessage());
mv.setViewName("error");
System.out.println("HelloController.handlerArithmeticException");
return mv;
}
}
当然也可以通过在myspringmvc-servlet.xml配置文件中添加Bean支持实现
<!-- 可以配置使用Spring提供的异常处理类 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 指定注入异常属性的key, 默认为 "exception" -->
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
7、日志集成
本章节介绍的是集成log4j2日志框架,首先pom中配置依赖jar
<!--log4j2支持集成日志框架-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
然后在相应的文件目录下编写log4j.xml模板文件,笔者的在resources下
<?xml version="1.0" encoding="UTF-8"?>
<!--
status:这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出。
monitorInterval : Log4j2能够自动检测修改配置文件和重新配置本身,设置间隔秒数,单位是s,最小是5s.
-->
<Configuration status="ERROR" monitorInterval="30">
<Properties>
<!-- 配置日志文件输出目录 -->
<Property name="LOG_HOME">/root/bubble/logs</Property>
<property name="ERROR_LOG_FILE_NAME">/root/bubble/logs</property>
</Properties>
<Appenders>
<!-- Console节点 配置控制台日志输出:
name:指定Appender的名字.
target: SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.
PatternLayout: 输出格式,不设置默认为:%m%n.
-->
<Console name="Console" target="SYSTEM_OUT">
<!-- ThresholdFilter 过滤器:
控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)
日志的级别: ALL< Trace < DEBUG < INFO < WARN < ERROR < FATAL < OFF。
-->
<ThresholdFilter level="TRACE" onMatch="ACCEPT" onMismatch="DENY" />
<!-- PatternLayout 日志输出格式模板:
%d{yyyy-MM-dd HH:mm:ss.SSS} 日志生成时间。
%-5level 日志级别(级别从左显示5个字符宽度)。
%logger{36} 表示logger名字最长36个字符,否则按照句点分割。
%L 日志输出所在行数 日志输出所在行数
[%t] 输出产生该日志事件的线程名
%msg 日志消息
%n 是换行符
eg:"2017-04-17 16:04:02.312 INFO com.zte.lucene.tools.DateUtils2Joda:424 [main] - Info Message!"
-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}:%L [%t] - %msg%n" />
</Console>
<!-- RollingFileAppender 定义输出滚动文件格式。(FileAppender 定义输出到文件)
name : RollingFileAppender的名字,用于与Loggers模块的绑定
fileName : 日志输出保存的文件路径
filePattern:满足条件后,日志输出保存的文件路径和名称。
(eg: 2017-04/search-2017-04-17-1.log)
-->
<RollingFile name="RollingFileInfo" fileName="${LOG_HOME}/search.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/search-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}:%L [%t] - %msg%n" />
<!-- Policies定义相关策略:-->
<Policies>
<!--TimeBasedTriggeringPolicy 基于时间的滚动策略:该策略主要是完成周期性的log文件封存工作。
interval: integer型,指定两次封存动作之间的时间间隔,默认是1 hour。
单位:以日志的命名精度来确定单位,比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟。
关键点在于 filePattern后的日期格式.
modulate: boolean型,说明是否对封存时间进行调制。
若modulate=true,则封存时间将以0点为边界进行偏移计算。
比如:modulate=true,interval=4hours,那么假设上次封存日志的时间为01:00,
则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00.
-->
<!-- log4j2的按天分日志文件 : search-%d{yyyy-MM-dd}.log -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
<!--SizeBasedTriggeringPolicy 基于对log文件大小的判断策略:
当log文件大于设定的阈值时,将触发封存动作。
可设定的log文件大小的单位有bytes、KB、MB或GB。
-->
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!--DefaultRolloverStrategy(属性如不设置,则默认为最多同一文件夹下7个文件):
fileIndex: String类型,有两个选择“max”或“min”。
设置为“max”意味着将最新的日志信息封存在序号较大的封存文件中。“min”则相反。
max: integer类型,封存文件的序号的最大值。(超过最大值时,将有文件被删除)
min: integer类型,封存文件的序号的起始值。
相当于min和max两个参数设置了一个保存窗口,超出这个窗口的日志文件将会被删除。
-->
<DefaultRolloverStrategy max="100" />
</RollingFile>
<RollingFile name="RollingFileError"
fileName="${ERROR_LOG_FILE_NAME}/search-error.log"
filePattern="${ERROR_LOG_FILE_NAME}/$${date:yyyy-MM}/search-error-%d{yyyy-MM-dd}.log">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}:%L [%t] - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
<DefaultRolloverStrategy max="100" />
</RollingFile>
</Appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<Loggers>
<!--过滤掉spring的一些无用的DEBUG信息-->
<logger name="org.springframework" level="INFO"></logger>
<!-- 配置日志的根节点 -->
<!-- level="all" 只能够输出level级别是all及all以上的-->
<root level="all">
<appender-ref ref="Console" />
<appender-ref ref="RollingFileInfo" />
<appender-ref ref="RollingFileError" />
</root>
</Loggers>
</Configuration>
然后在web.xml文件中,将日志文件配置到上下文中
<!-- 集成log4j2日志框架 -->
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>classpath:log4j2.xml</param-value>
</context-param>
完成以上配置就已经集成了log4j2框架。开始测试:
@Controller
@RequestMapping("/log")
public class LoggerRecordController {
//获取日志
private static final Logger LOGGER = LogManager.getLogger();
@Autowired
UserInfoService userInfoService;
@RequestMapping("/testLog1")
@ResponseBody
public ModelAndView testLog1(@RequestParam("username") String name) {
long startTime = System.currentTimeMillis();
ModelAndView modelAndView = new ModelAndView();
//访问数据库
List userInfoList = userInfoService.getUserInfoList();
LOGGER.info(userInfoList);
modelAndView.addObject("data", userInfoList);
modelAndView.setViewName("success");//跳转到/WEB-INF/views/success.jsp
LOGGER.info("获取name=" + name + "接口耗时:" + (System.currentTimeMillis() - startTime) + "ms");
return modelAndView;
}
}
测试结果,如下所示:
2020-02-09 20:15:59.608 INFO com.leo.controller.LoggerRecordController:38 [http-apr-8080-exec-7] - [UserInfo{id=3, name='晓玲', gender='女', age='22', remarks='工程师'}, UserInfo{id=4, name='晓玲', gender='女', age='24', remarks='工程师'}]
2020-02-09 20:15:59.631 INFO com.leo.controller.LoggerRecordController:41 [http-apr-8080-exec-7] - 获取name=leo825接口耗时:39ms
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72743.html