`
genius0182
  • 浏览: 37045 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

对JDK log日志的扩展

阅读更多

最近因为需要写了一个日志模块,主要功能是实现日志文件滚动(不限日志文件个数的滚动),还有就是记录日志信息。因为我功能有限,所以我没有选择log4j这样的日志扩展,而选择了jdk log扩展。

开发环境是netbean 6.8
下面是扩展JDK LOG的Handler的类 直接上代码了。

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
public class RollingFileHandler extends Handler {

    private MeteredStream meter;
    private boolean append;
    private int limit;       // zero => no limit.
    private int count;
    private String pattern;
    private LogManager manager = LogManager.getLogManager();
    private boolean doneHeader;
    private Writer writerHandler;
    private OutputStream output;
    ErrorManager error;
    private static int index = 1;

    @Override
    public synchronized void flush() {
        if (writerHandler != null) {
            try {
                writerHandler.flush();
            } catch (Exception ex) {
                // We don't want to throw an exception here, but we
                // report the exception to any registered ErrorManager.
                reportError(null, ex, ErrorManager.FLUSH_FAILURE);
            }
        }
    }

    private synchronized void flushAndClose() throws SecurityException {
        manager.checkAccess();
        if (writerHandler != null) {
            try {
                if (!doneHeader) {
                    writerHandler.write(getFormatter().getHead(this));
                    doneHeader = true;
                }
                writerHandler.write(getFormatter().getTail(this));
                writerHandler.flush();
                writerHandler.close();
            } catch (Exception ex) {
                // We don't want to throw an exception here, but we
                // report the exception to any registered ErrorManager.
                reportError(null, ex, ErrorManager.CLOSE_FAILURE);
            }
            writerHandler = null;
            output = null;
        }
    }

    /**
     * Change the output stream.
     * <P>
     * If there is a current output stream then the <tt>Formatter</tt>'s
     * tail string is written and the stream is flushed and closed.
     * Then the output stream is replaced with the new output stream.
     *
     * @param out   New output stream.  May not be null.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     */
    protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
        if (out == null) {
            throw new NullPointerException();
        }
        flushAndClose();
        output = out;
        doneHeader = false;
        String encoding = getEncoding();
        if (encoding == null) {
            writerHandler = new OutputStreamWriter(out);

        } else {
            try {
                writerHandler = new OutputStreamWriter(out, encoding);
            } catch (UnsupportedEncodingException ex) {
                // This shouldn't happen.  The setEncoding method
                // should have validated that the encoding is OK.
                throw new Error("Unexpected exception " + ex);
            }
        }
    }

    /**
     * Set (or change) the character encoding used by this <tt>Handler</tt>.
     * <p>
     * The encoding should be set before any <tt>LogRecords</tt> are written
     * to the <tt>Handler</tt>.
     *
     * @param encoding  The name of a supported character encoding.
     *	      May be null, to indicate the default platform encoding.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     * @exception  UnsupportedEncodingException if the named encoding is
     *		not supported.
     */
    public void setEncoding(String encoding)
            throws SecurityException, java.io.UnsupportedEncodingException {
        super.setEncoding(encoding);
        if (output == null) {
            return;
        }
        // Replace the current writer with a writer for the new encoding.
        flush();
        if (encoding == null) {
            writerHandler = new OutputStreamWriter(output);
        } else {
            writerHandler = new OutputStreamWriter(output, encoding);
        }
    }

    // A metered stream is a subclass of OutputStream that
    //   (a) forwards all its output to a target stream
    //   (b) keeps track of how many bytes have been written
    private class MeteredStream extends OutputStream {

        OutputStream out;
        int written;
        boolean doneHeader;
        Writer writer;

        MeteredStream(OutputStream out, int written) {
            this.out = out;
            this.written = written;
        }

        public void write(int b) throws IOException {
            out.write(b);
            written++;
        }

        public void write(byte buff[]) throws IOException {
            out.write(buff);
            written += buff.length;
        }

        public void write(byte buff[], int off, int len) throws IOException {
            out.write(buff, off, len);
            written += len;
        }

        public void flush() throws IOException {
            out.flush();
        }

        public void close() throws IOException {
            out.close();
        }
    }

    private void open(File fname, boolean append) throws IOException {
        int len = 0;
        if (append) {
            len = (int) fname.length();
        }
        FileOutputStream fout = new FileOutputStream(fname.toString(), append);
        BufferedOutputStream bout = new BufferedOutputStream(fout);
        meter = new MeteredStream(bout, len);
        setOutputStream(meter);

    }

    // Private method to configure a FileHandler from LogManager
    // properties and/or default values as specified in the class
    // javadoc.
    private void configure() {
        LogManager manager = LogManager.getLogManager();

        String cname = getClass().getName();

        pattern = "%h/java%u.log";
        limit = 0;
        if (limit < 0) {
            limit = 0;
        }
        append = false;
        setLevel(Level.ALL);
        setFilter(null);
        setFormatter(new SimpleFormatter());
        try {
            setEncoding(null);
        } catch (Exception ex) {
            try {
                setEncoding(null);
            } catch (Exception ex2) {
                // doing a setEncoding with null should always work.
                // assert false;
            }
        }
    }

    /**
     * Construct a default <tt>FileHandler</tt>.  This will be configured
     * entirely from <tt>LogManager</tt> properties (or their default values).
     * <p>
     * @exception  IOException if there are IO problems opening the files.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control"))</tt>.
     * @exception  NullPointerException if pattern property is an empty String.
     */
    public RollingFileHandler() throws IOException, SecurityException {
        manager.checkAccess();
        configure();
        openFiles();
    }

    /**
     * Initialize a <tt>FileHandler</tt> to write to the given filename.
     * <p>
     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
     * properties (or their default values) except that the given pattern
     * argument is used as the filename pattern, the file limit is
     * set to no limit, and the file count is set to one.
     * <p>
     * There is no limit on the amount of data that may be written,
     * so use this with care.
     *
     * @param pattern  the name of the output file
     * @exception  IOException if there are IO problems opening the files.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     * @exception  IllegalArgumentException if pattern is an empty string
     */
    public RollingFileHandler(String pattern) throws IOException, SecurityException {
        if (pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        manager.checkAccess();
        configure();
        this.pattern = pattern;
        this.limit = 0;
        this.count = 1;
        openFiles();
    }

    /**
     * Initialize a <tt>FileHandler</tt> to write to the given filename,
     * with optional append.
     * <p>
     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
     * properties (or their default values) except that the given pattern
     * argument is used as the filename pattern, the file limit is
     * set to no limit, the file count is set to one, and the append
     * mode is set to the given <tt>append</tt> argument.
     * <p>
     * There is no limit on the amount of data that may be written,
     * so use this with care.
     *
     * @param pattern  the name of the output file
     * @param append  specifies append mode
     * @exception  IOException if there are IO problems opening the files.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     * @exception  IllegalArgumentException if pattern is an empty string
     */
    public RollingFileHandler(String pattern, boolean append) throws IOException, SecurityException {
        if (pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        manager.checkAccess();
        configure();
        this.pattern = pattern;
        this.limit = 0;
        this.count = 1;
        this.append = append;
        openFiles();
    }

    /**
     * Initialize a <tt>FileHandler</tt> to write to a set of files.  When
     * (approximately) the given limit has been written to one file,
     * another file will be opened.  The output will cycle through a set
     * of count files.
     * <p>
     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
     * properties (or their default values) except that the given pattern
     * argument is used as the filename pattern, the file limit is
     * set to the limit argument, and the file count is set to the
     * given count argument.
     * <p>
     * The count must be at least 1.
     *
     * @param pattern  the pattern for naming the output file
     * @param limit  the maximum number of bytes to write to any one file
     * @param count  the number of files to use
     * @exception  IOException if there are IO problems opening the files.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     * @exception IllegalArgumentException if limit < 0, or count < 1.
     * @exception  IllegalArgumentException if pattern is an empty string
     */
    public RollingFileHandler(String pattern, int limit, int count)
            throws IOException, SecurityException {
        if (limit < 0 || count < 1 || pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        manager.checkAccess();
        configure();
        this.pattern = pattern;
        this.limit = limit;
        this.count = count;
        openFiles();
    }

    /**
     * Initialize a <tt>FileHandler</tt> to write to a set of files
     * with optional append.  When (approximately) the given limit has
     * been written to one file, another file will be opened.  The
     * output will cycle through a set of count files.
     * <p>
     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
     * properties (or their default values) except that the given pattern
     * argument is used as the filename pattern, the file limit is
     * set to the limit argument, and the file count is set to the
     * given count argument, and the append mode is set to the given
     * <tt>append</tt> argument.
     * <p>
     * The count must be at least 1.
     *
     * @param pattern  the pattern for naming the output file
     * @param limit  the maximum number of bytes to write to any one file
     * @param count  the number of files to use
     * @param append  specifies append mode
     * @exception  IOException if there are IO problems opening the files.
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     * @exception IllegalArgumentException if limit < 0, or count < 1.
     * @exception  IllegalArgumentException if pattern is an empty string
     *
     */
    public RollingFileHandler(String pattern, int limit, int count, boolean append)
            throws IOException, SecurityException {
        if (limit < 0 || pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        manager.checkAccess();
        configure();
        this.pattern = pattern;
        this.limit = limit;
        this.count = count;
        this.append = append;
        openFiles();
    }

    // Private method to open the set of output files, based on the
    // configured instance variables.
    private void openFiles() throws IOException {

        if (append) {
            File f = new File(pattern);
            try {
                open(f, true);
            } catch (IOException ex) {
                reportError(null, ex, ErrorManager.OPEN_FAILURE);
            }
        } else {
            rotate();
        }

    }

    // Rotate the set of output files
    private synchronized void rotate() {
        File target;
        File file;
        Level oldLevel = getLevel();
        setLevel(Level.OFF);
        close();
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss");
        String dateFormat = format.format(date);
        boolean renameSucceeded = true;
        if (count > 0) {
            file = new File(pattern + '_' + dateFormat + '.' + count);
            if (file.exists()) {
                index++;
                target = new File(pattern + '_' + dateFormat + "." + index);
                renameSucceeded = file.renameTo(target);
            }
            for (int i = count - 1; i >= 1 && renameSucceeded; i--) {
                file = new File(pattern + "." + i);
                if (file.exists()) {
                    target = new File(pattern + '.' + (i + 1));
                    renameSucceeded = file.renameTo(target);
                }
            }

            if (renameSucceeded) {
                // Rename fileName to fileName.1
                index = 1;
                target = new File(pattern + '_' + dateFormat + "." + 1);
                file = new File(pattern);
                renameSucceeded = file.renameTo(target);
                //
                //   if file rename failed, reopen file with append = true
                //
                if (!renameSucceeded) {
                    File f = new File(pattern);
                    append = true;
                    try {
                        open(f, append);
                    } catch (IOException ex) {
                        reportError(null, ex, ErrorManager.OPEN_FAILURE);
                    }
                }
            }
        }
        if (renameSucceeded) {
            File f = new File(pattern);
            try {
                open(f, false);
            } catch (IOException ex) {
                reportError(null, ex, ErrorManager.OPEN_FAILURE);
            }
        }
        setLevel(oldLevel);
    }

    /**
     * Format and publish a <tt>LogRecord</tt>.
     *
     * @param  record  description of the log event. A null record is
     *                 silently ignored and is not published
     */
    public synchronized void publish(LogRecord record) {

        if (!isLoggable(record)) {
            return;
        }
        String msg;
        try {
            msg = getFormatter().format(record);
        } catch (Exception ex) {
            // We don't want to throw an exception here, but we
            // report the exception to any registered ErrorManager.
            reportError(null, ex, ErrorManager.FORMAT_FAILURE);
            return;
        }

        try {
            if (!doneHeader) {
                writerHandler.write(getFormatter().getHead(this));
                doneHeader = true;
            }
            if (writerHandler == null) {
                File f = new File(pattern);
                open(f, append);
            }
            writerHandler.write(msg);

        } catch (Exception ex) {
            // We don't want to throw an exception here, but we
            // report the exception to any registered ErrorManager.
            reportError(null, ex, ErrorManager.WRITE_FAILURE);
        }
        flush();
        if (limit > 0 && meter.written >= limit) {
            // We performed access checks in the "init" method to make sure
            // we are only initialized from trusted code.  So we assume
            // it is OK to write the target files, even if we are
            // currently being called from untrusted code.
            // So it is safe to raise privilege here.
            AccessController.doPrivileged(new PrivilegedAction() {

                public Object run() {
                    rotate();
                    return null;
                }
            });
        }
    }

    /**
     * Close all the files.
     *
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     */
    public synchronized void close() throws SecurityException {
        flushAndClose();
    }

    private static class InitializationErrorManager extends ErrorManager {

        Exception lastException;

        public void error(String msg, Exception ex, int code) {
            lastException = ex;
        }
    }

    // Private native method to check if we are in a set UID program.
    private static native boolean isSetUID();
}

 然后是Util类的代码

import java.io.IOException;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Utils {

    private static Logger log;

    /**
     * @serial Class that issued logging call
     */
    protected static String sourceClassName;
    /**
     * @serial Method that issued logging call
     */
    protected static String sourceMethodName;
    private transient boolean needToInferCaller;

    static {
        inferCaller();
        Handler handler = configure("log.log",1000,1,true);
        try {
            log = Logger.getLogger(sourceClassName);

            log.addHandler(handler);

            log.setLevel(Level.ALL);

        } catch (Exception ex) {
            System.out.println("can't init the Logger, caused by: " + ex);
        }
    }

    public static void debug(String info) {
        inferCaller();

        log.logp(Level.SEVERE, sourceClassName, sourceMethodName, info);

    }

    public static void debug(String info,Throwable thrown){
        inferCaller();

        log.logp(Level.SEVERE, sourceClassName, sourceMethodName, info,thrown);
    }

    public static void info(String info) {
        inferCaller();
        log.logp(Level.INFO, sourceClassName, sourceMethodName, info);
        
    }

     public static void info(String info,Throwable thrown){
        inferCaller();

        log.logp(Level.INFO, sourceClassName, sourceMethodName, info,thrown);
    }

    public static void warning(String info) {
        inferCaller();
        log.logp(Level.WARNING, sourceClassName, sourceMethodName, info);
    }

     public static void warning(String info,Throwable thrown){
        inferCaller();

        log.logp(Level.WARNING, sourceClassName, sourceMethodName, info,thrown);
    }

    public static void error(String info) {
        inferCaller();
        log.logp(Level.SEVERE, sourceClassName, sourceMethodName, info);
    }

     public static void error(String info,Throwable thrown){
        inferCaller();

        log.logp(Level.SEVERE, sourceClassName, sourceMethodName, info,thrown);
    }
private static void init() {
        inferCaller();

        log = Logger.getLogger(Utils.sourceClassName);
    }

    // Private method to infer the caller's class and method names
    private static void inferCaller() {
//	needToInferCaller = false;
        // Get the stack trace.
        StackTraceElement stack[] = (new Throwable()).getStackTrace();
        // First, search back to a method in the Logger class.
        int ix = 0;
        while (ix < stack.length) {
            StackTraceElement frame = stack[ix];
            String cname = frame.getClassName();
            if (cname.equals("com.lhsm.logger.Utils")) {
                stack[ix] = stack[2];
                break;
            }
            ix++;
        }
        // Now search for the first frame before the "Logger" class.
        while (ix < stack.length) {
            StackTraceElement frame = stack[ix];
            String cname = frame.getClassName();
            if (!cname.equals("com.lhsm.logger.Utils")) {
                // We've found the relevant frame.
                sourceClassName = cname;
                sourceMethodName = frame.getMethodName();

                return;
            }
            ix++;
        }
        // We haven't found a suitable frame, so just punt.  This is
        // OK as we are only committed to making a "best effort" here.
    }

    /**
     *
     * @param pattern 为生成的输出文件名称指定一个模式。
     * @param limit   指定要写入到任意文件的近似最大量(以字节为单位)。如果该数为 0,则没有限制(默认为无限制)。.不能小于0
     * @param count   (1为不限滚动),这里指定个数滚动文件没有实现
     * @param append  指定是否应该将 FileHandler 追加到任何现有文件上。
     * @return
     */
    public static Handler configure(String pattern,int limit,int count,boolean append) {
        Handler handler = null;
        if (limit < 0 ||  pattern.length() < 1) {
	    throw new IllegalArgumentException();
	}
        
        try {
            handler = new RollingFileHandler(pattern, limit, count, append);
        } catch (IOException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        }
        return handler;
    }

    /**
     * @return the sourceClassName
     */
    public String getSourceClassName() {
        if (needToInferCaller) {
            inferCaller();
        }
        return sourceClassName;
    }

    /**
     * @return the sourceMethodName
     */
    public String getSourceMethodName() {
        if (needToInferCaller) {
            inferCaller();
        }
        return sourceMethodName;
    }
}

 

下面是一个测试Foo类

public class Foo {
    private int i =0;
    public Foo(int i) {
        this.i = i;
    }

    public void doIt() {

        Utils.debug("Debug..."+i);
        Utils.info("Info..."+i);
        Utils.warning("Warn..."+i);
        Utils.error("Error..."+i);
    }

    

    public void doFooIt() {
        Utils.debug("Debug..."+i);
        Utils.info("Info..."+i);
        Utils.warning("Warn..."+i);
        Utils.error("Error..."+i);
    }
}

 

public class LogTest {

    public static void main(String[] args) {
       for (int i = 0; i < 10000; i++) {
        Foo foo = new Foo(i);

        foo.doIt();
        foo.doFooIt();
        }

    }
}

 

以上就是实现的全部代码

0
0
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    druid-0.2.9.jar

    1) 可以监控数据库访问性能,Druid内置提供了一个功能强大的...4) SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。

    Druid是一个JDBC组件,它包括三部分 高效可管理的数据库连接池.rar

    4) SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid...

    ApkIDE——安卓反编译

    1、增加对apktool2.x版本的支持(目前apktool2.x仍然是测试版本,此版要求JDK1.7或以上),同时保留对1.5.2版的支持,二者可以一键切换(菜单「工具」-「配置与选项」-「选项」-「ApkTool版本切换」)。 2、增加apk...

    Druid jar 阿里数据库

    包含了druid官方druid-1.0.4.jar druid-1.0.4-javadoc.jar ...4) SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。

    阿里巴巴的开源项目JDBC连接池、监控组件 Druid.zip

     4) SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过...

    一个基于Python和Flume的日志收集和解析系统+源代码+文档说明

    * **扩展性良好**:既利用了flume强大的拓扑结构,比如:扇入、扇出等功能。又利用了Python高效的开发效率。同时,可以很方便的自定义parser回调函数 --- ### 架构 架构图" src=...

    java利用JMX做出不一样的的JVM.docx

    JMX 全称为 Java Management Extensions,翻译过来就是 Java 管理...有标准、有规范是为了让开发者可以定制开发自己的扩展功能,而且作为一个框架来讲,JDK 已经帮我们实现了常用的功能,尤其是对 JVM 的监控和管理。

    心跳检测(如Tomcat,Jetty)的JAVA 微服务应用程序.rar

    有趣的是log5j主页对自己名字的解释,因为要感谢JDk 1.5,所以才叫了这个名字。  更多log5j信息  JFinal 事件驱动插件 JFinal-event  JFinal-event是JFinal框架的一个事件驱动插件,其核心目标是深层次解耦,...

    小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”

    模块 介绍 hutool-aop JDK动态代理封装,...hutool-log 自动识别日志实现的日志门面 hutool-script 脚本执行封装,例如Javascript hutool-setting 功能更强大的Setting配置文件和Properties封装 hutool-system 系统参

    Baishop是一款B2C电子商务网站.zip

    二进制日志(Binary Log,binlog):记录对数据库进行数据更改(如INSERT、UPDATE、DELETE)的操作序列,用于数据复制和恢复。 查询日志(query log):可选地记录所有发送到MySQL服务器的SQL查询,用于调试和审计...

    RequestCorrelation:** 已弃用** 该项目是一个 Java 库,有助于为微服务建立和跟踪关联 id

    扩展(Log4J 和 Logback)以确保在日志中发布关联 id 系统要求 Java JDK 6.0 或更高版本(它是在 JDK 7 下使用 1.6 作为目标源编译的)。 Apache Commons Lang 3.0 或更高版本 Log4J V1.x 或 Logback 日志记录配置...

    windows_server2003+tomcat+iis6整合

    log_file c:\tomcat6\logs\isapi.log (指定JK插件使用的日志文件) log_level debug (指定日志级别) worker_file c:\tomcat6\conf\workers.properties (指定JK插件的工作文件) worker_mount_file c:\tomat6\conf\...

    web开发常用jar

    通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器 jxl-2.6.jar 通过java操作excel表格的工具类库 jta-1.1.jar Java事务API,为J2EE平台提供了分布式事务服务 ...

    智能开发平台 DOROODO

    2.希望你在使用doroodo的时候,能够贡献你的建议和扩展代码。 【安装】 1.需要软件: [ide] 假如你需要使用工作流,可以使用fixflow团队封装的eclipse(http://www.fixflow.org/) 若不需要,你可以直接使用eclipse ...

    xmljava系统源码-phone:这只是一套简化开发的框架,主要技术使用Mybatis+Spring+SpringMVC+shiro,全局鉴

    使用slf4j+log4j做日志记录 使用druid做连接池及监控 采用mysql作为数据库 使用kaptcha并二次开发作为验证码 使用maven作为jar管理 使用redis作为缓存 使用poi导出excel 项目亮点: 严格的权限控制,当然你也可以自己...

    【毕业设计】企业员工绩效考评APP的设计与实现.zip

    daily_log(工作日志表) 字段:自增id, emp_id(外键关联employee), content, create_time, last_upd_time, status(0未审阅,1已审阅) project(项目表) 字段:自增prj_id, create_time, finish_time, prj_...

    java开发常用jar包

    通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器 jxl-2.6.jar 通过java操作excel表格的工具类库 jta-1.1.jar Java事务API,为J2EE平台提供了分布式事务服务 ...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    jdk logger 测试框架 测试框架 junit easymock testng mockito bug管理 禅道 jira 开发工具 编程工具 eclipse myeclipse idea vi VS webstorm sublime text 版本控制 svn git 项目管理 ...

    java外卖ssm项目源码-NeuSoft-Cloud-Hospital:东软医院信息系统(HIS)

    JDK 1.8 SSM Spring 自动装配与控制反转 Spring MVC 数据有效性校验 数据回显 异常处理 拦截器 MyBatis MyBatis Generator 生成 bean 与 SQL 语句 MyBatis 数据库连接池 PageHelper: MyBatis 的分页插件 MySQL 关系...

Global site tag (gtag.js) - Google Analytics