SpringMVC学习(二)——快速搭建SpringMVC开发环境(注解方式)

导读:本篇文章讲解 SpringMVC学习(二)——快速搭建SpringMVC开发环境(注解方式),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

说明

本文主要是通过注解方式搭建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、前面两个RequestMappingHandlerMappingBeanNameUrlHandlerMapping是HandlerMapping接口的实现类,用来处理请求映射的。

  • 第一个是处理@RequestMapping注解的。
  • 第二个会将Controller类的名称映射为请求的url。

2、中间三个RequestMappingHandlerAdapterHttpRequestHandlerAdapterSimpleControllerHandlerAdapter是用来处理请求的。就是调用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

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!