【斗医】【3】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://qingkechina.blog.51cto.com/5552198/1308932

在上面提及异常的中英文从资源文件中读取,若读取失败需要日志记录,所以使用网上正在闹腾的Logback来记录。关于Logback与Log4j这里不做评判和说明,所有疑问可以请教谷歌。

一、Logback的使用前期准备

1、在官网http://logback.qos.ch/download.html下载Logback;在官网http://www.slf4j.org/download.html下载slf4j

2、在D:\medical\war\WEB-INF下创建lib文件夹,用于放置本应用的所需JAR包

3、解压上面的下载,把logback-access-1.0.13.jar、logback-classic-1.0.13.jar、logback-core-1.0.13.jar和slf4j-api-1.7.5.jar复制到D:\medical\war\WEB-INF\lib中

二、测试类

下面着手写一个与本应用无关的测试类FrameLogger.java

1、打开Eclipse,在medical工程上右键,选择“New > Class”,Package填写“com.medical.frame”,Name填写“FrameLoggerDemo”,点击“Finish”

2、要使用日志类,应用先定义一个Logger,然后再使用这个对象,所以代码如下:


1

2

3

4

5

6

7

8

9

10

11

12

package com.medical.frame;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class FrameLoggerDemo

{

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

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             

    public static void main(String[] args)

    {

        logger.info("It's test for logback.");

    }

}

3、你会发现上面代码编译不通过。这很正常,因为Eclipse没有导入所需的jar包。右键medical工程选择“Properties > Java Build Path > Libraries > Add JARs...”,在JAR选择窗口中把D:\medical\war\WEB-INF\lib下的jar包添加进来,如图:

4、我想不仅把日志打印到控制台还要打印到日志文件中,更甚者想插入到数据库中,XML配置文件可以协助完成。在D:\medical\war\下创建etc文件夹,然后在etc下创建logconfig.xml文件。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <!--日志文件的存储地址,一定要使用绝对路径-->

    <property name="LOG_HOME" value="D:/log" />

    <!--日志文件后缀格式-->

    <timestamp key="fileSuffix" datePattern="yyyyMMdd'_'HHmm" />

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

    <!--控制台输出-->

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

        <!--输出在控制台上的日志字符串编码-->

        <Encoding>UTF-8</Encoding>

        <!--输出在控制台上的日志格式-->

        <layout class="ch.qos.logback.classic.PatternLayout">

            <!--%d表示日期; %thread表示线程名; %-5level表示从左显示5个字符宽度的级别名; %logger表示日志类; %msg表示日志消息; %n表示换行-->

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{60} - %msg%n</pattern>

        </layout>

    </appender>

    <!--文件输出-->

    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!--输出在控制台上的日志字符串编码-->

        <Encoding>UTF-8</Encoding>

        <!--日志对应的文件名-->

        <file>${LOG_HOME}/trace${fileSuffix}.txt</file>

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

        <!--日志文件记录滚动策略-->

        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">

            <!--当日志文件超过大小时就压缩为zip包-->

            <fileNamePattern>${LOG_HOME}/trace${fileSuffix}.%i.zip</fileNamePattern>

            <!--最多有10个zip压缩包,超过10就覆盖之前的-->

            <minIndex>1</minIndex>

            <maxIndex>10</maxIndex>

        </rollingPolicy>  

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

        <!--文件超过5M就重新生成新的日志文件,老的日志文件压缩成zip包-->

        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">

            <maxFileSize>5MB</maxFileSize>

        </triggeringPolicy>

        <!--输出在文件上的日志格式-->

        <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{60} - %msg%n </pattern>

        </encoder>

    </appender>

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

    <!--日志输出级别-->

    <root level="INFO">

        <appender-ref ref="STDOUT" />

        <appender-ref ref="FILE" />

    </root>

</configuration>



【备注】:关于这个配置文件建议感兴趣的读者,自己亲自配置一下,这样才能体验每个标签的含义。



5、运行FrameLoggerDemo发现并没有在指定的D:/log下输出日志文件。试想一下,我们都没有告诉Logback输出策略是什么,它怎么又会知道呢?所以这里需要在main()运行之前把logconfig.xml加载进来,怎么加载?怎么只加载一次?方法很多,可以使用Spring的单例工厂,而这里我们使用单例类。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

private static FrameLoggerDemo instance = new FrameLoggerDemo();

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

private FrameLoggerDemo()

{

    String logbackCfg = "D:\\medical\\war\\etc\\logconfig.xml";

    ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();

    JoranConfigurator configurator = new JoranConfigurator();

    configurator.setContext((LoggerContext) loggerFactory);

    try

    {

        configurator.doConfigure(logbackCfg);

    }

    catch (JoranException e)

    {

        e.printStackTrace();

    }

}

再运行一次,有日志文件输出出来了

三、斗医应用如何使用Logback呢?

从上面的FrameLoggerDemo可以看到,系统在使用Logger对象之前必须把配置文件加载进来,对于web应用它由多个Servlet构成,所以最好在第一个Servlet启动时加载进来,后续的使用者就直接使用即可。

1、在D:\medical\war\WEB-INF\web.xml中定义名称为action的servlet


1

2

3

4

5

6

7

8

9

10

11

12

13

14

<web-app>

    <servlet>

        <servlet-name>action</servlet-name>

        <servlet-class>com.medical.frame.FrameLauncher</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>action</servlet-name>

        <url-pattern>*.act</url-pattern>

    </servlet-mapping>

    <welcome-file-list>

         <welcome-file>index.html</welcome-file>

    </welcome-file-list>

</web-app>

2、该servlet说明当客户端的请求为*.act时,都使用名称为action的servlet处理,处理器为FrameLauncher这个类,它必须继承HttpServlet。Servlet一般由init、doGet、doPost、destory方法构成,所以FrameLauncher也不例外,它需要重写这4个方法。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

package com.medical.frame;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

/**

 * 斗医系统动作登陆类

 */

public class FrameLauncher extends HttpServlet

{

    @Override

    public void init() throws ServletException

    {

                                                                                                                                                                                                                                                                                                                                                                                                                            

    }

                                                                                                                                                                                                                                                                                                                                                                                                                        

    @Override

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException

    {

                                                                                                                                                                                                                                                                                                                                                                                                                            

    }

                                                                                                                                                                                                                                                                                                                                                                                                                        

    @Override

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException

    {

        doGet(request, response);

    }

                                                                                                                                                                                                                                                                                                                                                                                                                        

    @Override

    public void destroy()

    {

                                                                                                                                                                                                                                                                                                                                                                                                                            

    }

}

3、当request请求到达Web容器时,它会根据请求参数判断使用哪个servlet处理,当servlet首次被调用到时,它会反射<servlet-class>定义的类,再调用init()方法进行初始化。而我们的日志加载就可以在这里处理。

定义com.medical.frame.util.FrameConfigUtil.java,里面定义静态方法initLogConfig()用于加载logback日志配置文件。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

public class FrameConfigUtil

{

    /**

     * 加载Logback日志配置文件

     */

    public static void initLogConfig(ServletContext context)

    {

        // 获取logback配置文件

        StringBuilder logConfigPath = new StringBuilder(context.getRealPath("/"));

        logConfigPath.append("etc").append(File.separator).append("logconfig.xml");

                                                                                                                                                                                                                                                                                                                                      

        // 加载logback配置文件

        ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();

        JoranConfigurator configurator = new JoranConfigurator();

        configurator.setContext((LoggerContext) loggerFactory);

        try

        {

            configurator.doConfigure(logConfigPath.toString());

        }

        catch (JoranException e)

        {

            System.out.println("[重要] init logback config error.\n" + e.getMessage());

        }

    }

}

4、FrameLauncher.init()方法调用FrameConfigUtil.initLogConfig()


1

2

3

4

5

6

@Override

public void init() throws ServletException

{

    ServletContext context = getServletContext();

    FrameConfigUtil.initLogConfig(context);

}

至此logback的配置文件在action这个servlet初始化时就加载完了,那该如何测试呢?

5、修改D:\medical\war\index.html文件内容,修改后的内容如下:


1

2

3

4

5

6

7

8

<html>

    <head>

        <title>medical</title>   

    </head>

    <body>

        <a href="index.act">Test Logback</a>

    </body>

</html>

6、重写com.medical.frame.FrameLauncher.doGet()方法


1

2

3

4

5

6

7

8

9

/**

 * 定义日志对象

 */

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

@Override

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException

{

    logger.error("It's test for logback.");

}

这样当在浏览器中输入http://localhost:8080/medical时,由web.xml的<welcome-file-list>定义知系统首先加载index.html文件,当用鼠标点击Test Logback会index.act的HTTP请求发送给Tomcat容器,Tomcat根据web.xml的<url-pattern>*.act</url-pattern>找到对应的<servlet-name>action</servlet-name>,然后反射加载com.medical.frame.FrameLauncher.java,当FrameLaucher加载时调用init()方法把logconfig.xml读入,接着把HTT请求转换为HttpServletReqeust请求交给doGet(),从而把日志打印出来。



【备注1】:若用户从头到尾地写这个应用,有可能会发现,尽管在D:\log下生成了日志文件,但里面没有内容,这有可能是在加载logconfig.xml时使用的JoranConfigurator不正确。应该使用import ch.qos.logback.classic.joran.JoranConfigurator,而非import ch.qos.logback.access.joran.JoranConfigurator。

【备注2】:若在实际操作这个实例时遇到问题,可参见附件,也可评论以便及时交流


本文出自 “青客” 博客,请务必保留此出处http://qingkechina.blog.51cto.com/5552198/1308932

时间: 2024-11-11 03:13:08

【斗医】【3】Web应用开发20天的相关文章

【斗医】【17】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1543919     细心的读者可能已发现"Web应用开发50天"改为了"Web应用开发20天",之所以这样调整是因为当时想前20篇只讲解Web基础知识,中间10篇讲解我一直想要封装的Web框架,后20篇将该应用转换为Android应用.但由于最近女儿出生,业余时间都被她占用了,

【斗医】【7】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1330647 现在想想一下首页放置哪些内容?由于该WEB应用的聚集点在"斗"上,也就是对医术的探讨方面,个人认为应该是对展示较新的或评价较好的病症药方的展示方面.这里包含两部分:(1)数据的获取,即动态读取较好或评价较好的药方数据:(2)页面的展示,即静态页面布局和数据显示. 对于第一个问题会涉及到

【斗医】【9】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1377044 一.调试<[斗医][8]Web应用开发50天>数据表映射方法    本来想把数据库配置.Hibernate连接封装和映射配置一块写的,但由于个人时间问题时断时续,思路也多次被打断,所以在此对其进行弥补.    若读者把上篇的附件下载下来运行,会发现运行失败,下面随着异常分析并解决. 1.截止目

【斗医】【11】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1386941 本文在上文的基础上完成用户登录验证功能. 四.获取数据请求业务处理封装 1.配置数据读取方式,它的作用是使用FrameDataGainer响应以.data结尾的请求,并把处理后的数据返回给客户端.打开D:\medical\war\WEB-INF\web.xml文件,填充如下内容: 1 2 3 4

【斗医】【12】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1390410 在上文中有意埋了几个安全彩蛋,以便后面在聊网络安全时使用. 书接前言,对上文做过实践的朋友肯定会发现:当用户注册/登录成功后页面跳转到了系统首页,但首页的导航菜单并没有显示用户名.本文重点实现这个特性,同时也谈谈系统的编码问题. 六.注册/登录成功后导航菜单显示当前用户名    与JSP不同之处

【斗医】【6】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1322419 对于一个网站来讲均会存在公共页面,如异常页面.系统菜单等等,本章针对斗医系统菜单做一下介绍.可以想一想常见网站的系统菜单形式,一般都是菜单项在每个页面的内容不变,区别是菜单的选择状态不同. JSP可以使用<%@ include file="">语句把公共系统菜单页面引进来,

【斗医】【4】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1315778 在上面把日志文件打印到了D:\log下,考虑到Liunx服务器环境下,让最终用户修改可能不可接受,接下来完成三件事情:(1)应用程序指定输出路径(2)完善异常类的处理(3)完成页面跳转的封装处理 一.指定输出路径 由于Logback的<FILE>指定相对路径与Log4J存在差异,所以在修改日志

【斗医】【5】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1317441 三.页面跳转封装 [接上]在< 接下来要完成如下功能: Web容器(Tomcat)接受到HTTP请求后,Web容器把HTTP转换为HttpServletRequest对象,然后根据请求名称匹配规则找到相应的Servlet,调用servlet-class对应类的doGet()或doPost()方法

【斗医】【1】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1303925 从哪里开始呢? 还是从前段认识的朋友开始吧. 前段在圈里认识了一个朋友,当他聊到他用SSH开发了一套系统时,我思想意识中想到SSH应该是一个通讯协议,他用不可置否的语气说:大叔,你从事这一行业也这么多年了,难道不知道SSH? 说来惭愧,从事这行业时间真的不短了,好像没有真的从事过WEB方面的开发