easyui+springboot+jpa实现一个简单的后台管理系统
1.首先,添加依赖,配置yml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.32</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.22</version> </dependency> </dependencies>
yml:
server: port: 8081 servlet: context-path: / spring: http: encoding: force: true charset: UTF-8 freemarker: suffix: .ftl cache: false request-context-attribute: request charset: UTF-8 template-loader-path: classpath:/view/ check-template-location: false profiles: active: config mvc: static-path-pattern: /static/** datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://xx.xxx.xxx:3306/game?useUnicode=true&characterEncoding=UTF-8mb4&useSSL=false username: xxx password: xxx jpa: database: mysql show-sql: true
整体的截图:
static里面放的是静态资源,yml里static-path-pattern是配置了静态资源的路径
inc文件夹中放置了inc.ftl 调用了一些样式,方便其他页面的调用静态资源
inc.ftl:
<script src="${request.contextPath}/static/jquery/jquery.min.js"></script> <script src="${request.contextPath}/static/jquery/jquery.form.js"></script> <!--easyui --> <!-- easyui.css放前面 --> <link rel="stylesheet" type="text/css" href="${request.contextPath}/static/easyui/themes/styles/default/easyui.css" rel="stylesheet" title="default"> <link rel="stylesheet" type="text/css" href="${request.contextPath}/static/easyui/themes/styles/black/easyui.css" rel="stylesheet" title="black"> <link rel="stylesheet" type="text/css" href="${request.contextPath}/static/easyui/themes/styles/bootstrap/easyui.css" rel="stylesheet" title="bootstrap"> <link rel="stylesheet" type="text/css" href="${request.contextPath}/static/easyui/themes/styles/gray/easyui.css" rel="stylesheet" title="gray"> <link rel="stylesheet" type="text/css" href="${request.contextPath}/static/easyui/themes/styles/metro/easyui.css" rel="stylesheet" title="metro"> <link rel="stylesheet" href="${request.contextPath}/static/easyui/themes/icon.css" /> <link rel="stylesheet" href="${request.contextPath}/static/easyui/themes/color.css" /> <script src="${request.contextPath}/static/easyui/jquery.easyui.min.js"></script> <script src="${request.contextPath}/static/easyui/datagrid-detailview.js"></script> <script src="${request.contextPath}/static/easyui/easyui-lang-zh_CN.js"></script> <script src="${request.contextPath}/static/easyui/extEasyUI.js" charset="utf-8"></script> <script src="${request.contextPath}/static/jquery/jquery.serializejson.js"></script> <#--<!--自定义样式 –>--> <link rel="stylesheet" href="${request.contextPath}/static/manager/css/global.css" /> <script src="${request.contextPath}/static/manager/js/global.js"></script> <link rel="stylesheet" href="${request.contextPath}/static/manager/css/img.css" /> <script src="${request.contextPath}/static/manager/js/img.js"></script>
其他页面只需要在<head>中加入
<#include "inc/inc.ftl"/>,就能调用和inc一样的静态资源
2.完成登陆/修改密码/退出系统的功能和工具类/页面的编写
login.ftl就不放了
index.ftl:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <title>ace Admin</title> <meta name="description" content=""/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <#include "inc/inc.ftl"/> </head> <body> <div id="test"></div> <div class="easyui-layout" data-options="fit:true"> <div data-options="region:'north'" class="head_body" style="overflow:hidden;"> <div> <div class="head_left"></div> <div class="head_right"> <div class="huanying"> 欢迎 <span>${Session.userInfo.username}</span> 登陆 | 现在是<span id="show_date"></span> </div> <div class="anniu"> <div class="bb"> <a href="javascript:logout();" class="logout"></a> <a id="open_change_password" class="changePwd" href="javascript:editPassword();"></a> </div> <div class="bs"> <a class="styleswitch a1" style="CURSOR: pointer" title="黑灰色" rel="black"></a> <a class="styleswitch a2" style="CURSOR: pointer" title="天蓝色" rel="default"></a> <a class="styleswitch a3" style="CURSOR: pointer" title="灰色" rel="bootstrap"></a> <a class="styleswitch a4" style="CURSOR: pointer" title="浅灰色" rel="gray"></a> <a class="styleswitch a5" style="CURSOR: pointer" title="白色" rel="metro"></a> </div> </div> </div> </div> </div> <div data-options="region:'west',split:true,title:'导航菜单'" style="width:188px;"> <div class="easyui-accordion" id="main-accordion" data-options="fit:true,border:false"> <ul> <li><a href="javascript:void(0)" class="easyui-linkbutton" onclick="addTab('设置一级权重','resources/to_setting')">设置一级权重</a></li> <li><a href="javascript:void(0)" class="easyui-linkbutton" onclick="addTab('设置二级权重','resources/to_detailSetting')">设置二级权重</a></li> <li><a href="javascript:void(0)" class="easyui-linkbutton" onclick="addTab('设置游戏道具','resources/to_gameProp')">设置游戏道具</a></li> </ul> </div> </div> <div id="mainPanel" data-options="region:'center'"> <div id="index_tabs" class="easyui-tabs" data-options="fit:true,border:false,tabHeight:30" style="height:600px;"> <div title="Home"> <div style="padding:10px 0 10px 10px"> <h2>系统介绍</h2> <div class="light-info"> </div> </div> </div> </div> </div> </div> <div id="dlg" class="easyui-dialog" style="width:450px;height:auto;padding:10px 20px" buttons="#dlg-buttons" data-options="closed:true,modal:true"> <form id="fm" method="post" enctype="multipart/form-data"> <input type="hidden" id="userId" name="userId"/> <table class="grid"> <tr> <td>请输入新密码:</td> <td> <input type="text" name="password" class="easyui-passwordbox" iconWidth="28" data-options="required:true,validType:['length[0,20]']"/> </td> </tr> </table> </form> </div> <div id="dlg-buttons"> <a href="javascript:void(0)" class="easyui-linkbutton c8" data-options="iconCls:'icon-ok'" onclick="javascript:saveUser();" style="width:90px;">保存</a> <a href="javascript:void(0)" class="easyui-linkbutton c2" data-options="iconCls:'icon-cancel'" onclick="javascript:$('#dlg').dialog('close');" style="width:90px;">取消</a> </div> </body> </html> <script type="text/javascript"> $(document).ready(function () { var myDate = new Date(); var week = ['日', '一', '二', '三', '四', '五', '六']; var month = myDate.getMonth() + 1; var weekDay = " 星期" + week[myDate.getDay()]; var showDate = myDate.getFullYear() + "年" + month + "月" + myDate.getDate() + "日" + weekDay; $("#show_date").text(showDate); }); //初始化TABS组件 $('#index_tabs').tabs({ fit: true, border: false, tabHeight: 30, tools: [{ iconCls: 'icon-reload', handler: function () { var currTab = $('#index_tabs').tabs('getSelected'); var index = $('#index_tabs').tabs('getTabIndex', currTab); if (index != 0) { var updateUrl = $(currTab.panel('options').content).attr('src'); $('#index_tabs').tabs('update', { tab: currTab, options: { content: refreshTab(updateUrl) } }); } } }, { iconCls: 'icon-clear', handler: function () { $.messager.confirm('提示', '确定要全部关闭选项卡?', function (r) { if (r) { var tabTitle = new Array(); var tabs = $('#index_tabs').tabs("tabs"); var tCount = tabs.length; if (tCount > 0) { for (var i = 0; i < tCount; i++) { tabTitle.push(tabs[i].panel('options').title); } for (var i = 0; i < tabTitle.length; i++) { if (tabTitle[i] != '首页') { $('#index_tabs').tabs("close", tabTitle[i]); } } } } }); } }] }); function editPassword() { $('#dlg').dialog('open').dialog('setTitle', '修改'); $("#userId").val(${Session.userInfo.id}); } function saveUser() { $('#fm').form('submit', { url: "${request.contextPath}/user_save", success: function (result) { var result = eval('(' + result + ')'); if (result.code == 0) { $.messager.show({ title: '提示', msg: result.message }); $('#dlg').dialog('close'); } } }); } </script>
页面截图:
登陆/修改密码/退出系统功能的控制层:
package com.yz.slotsgameht.controller; import com.yz.slotsgameht.domain.SysUser; import com.yz.slotsgameht.service.SysUserService; import com.yz.slotsgameht.utils.GetIpAddress; import com.yz.slotsgameht.utils.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * @Author: Lukizzz * @Date: 2018/8/28 14:19 * @Description: */ @Controller public class SysUserController { private final Logger log = LoggerFactory.getLogger(SysUser.class); @Autowired private SysUserService sysUserService; @RequestMapping("/login") public String login2() { return "login"; } @RequestMapping(value = "/do_login") public String login(String username, String password, HttpServletRequest request) { SysUser user = sysUserService.getUserByLogin(username); HttpSession session = request.getSession(); String xIp = GetIpAddress.getIpAddress(request); log.info("账号: {},密码: {},本地ip:{}", username, password, xIp); if (user == null) { request.setAttribute("errorInfo", "用户名不存在"); return "login"; } else if (user.getPassword().equals(password)) {
//将获取的user数据存入session中,名字为"userInfo" session.setAttribute("userInfo", user); return "redirect:/index"; } else { request.setAttribute("errorInfo", "用户名密码错误"); return "login"; } } @RequestMapping(value = "/logout") public String logout(HttpServletRequest request) { HttpSession session = request.getSession(); session.removeAttribute("userInfo"); return "login"; } @RequestMapping(value = "/index") public String index() { return "index"; } @RequestMapping(value = "/user_save") @ResponseBody public Result saveUser(Long userId,String password,HttpServletRequest request){
//获取ip地址 String ip = GetIpAddress.getIpAddress(request);
//日志 log.info("新密码: {},本地ip地址:{}", password, ip); sysUserService.saveUser(userId, password); return Result.builder(); } }
Result工具类:
package com.yz.slotsgameht.utils; import lombok.Data; /** * @Author: Lukizzz * @Date: 2018/8/29 16:02 * @Description: */ @Data public class Result<T> { private int code = 0; private String message; private T data; private CodeMsg codeMsg = CodeMsg.SUCCESS; public static Result builder(CodeMsg codeMsg) { Result result = new Result(); result.setCode(codeMsg.getCode()); result.setMessage(codeMsg.getMsg()); return result; } public static Result builder() { return builder(CodeMsg.SUCCESS); } public Result withCode(CodeMsg codeMsg) { message = codeMsg.getMsg(); code = codeMsg.getCode(); return this; } public Result withData(T data) { this.data = data; return this; } public Result() { this.code = codeMsg.getCode(); this.message = codeMsg.getMsg(); } public Result(CodeMsg codeMsg) { this.code = codeMsg.getCode(); this.message = codeMsg.getMsg(); } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } public void setCodeMsg(CodeMsg codeMsg) { this.codeMsg = codeMsg; } }
CodeMsg工具类:
package com.yz.slotsgameht.utils; /** * @author admin * @date 2017/8/24 */ public enum CodeMsg { SUCCESS(0, "成功"), FAIL(1, "未知错误"), USER_PWD_ERROR(1000, "用户名密码错误"), CHANNEL_EXIST(1001, "已存在此代理渠道"), SUBCHANNEL_EXIST(1002, "已存此在渠道"), USERNAME_EXIST(1003, "此用户名已存在"), UID_NOT_EXIST(1004, "UID不存在"), FID_NOT_EXIST(1005, "FID不存在"), ANCHOR_NOT_EXIST(1006, "主播不存在"), BOTTOM(10000000, "垫底"); private int code; private String msg; CodeMsg(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
从Http中解析request获取ip地址
package com.yz.slotsgameht.utils; import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; /** * @Author: Lukizzz * @Date: 2018/8/30 10:13 * @Description: */ public class GetIpAddress { public static String getIpAddress(HttpServletRequest request) { String ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) { // 根据网卡取本机配置的IP InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress = inet.getHostAddress(); } } if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; } }
3.修改游戏设置功能(以修改道具名称和兑换金币为例)
控制层:
package com.yz.slotsgameht.controller; import com.yz.slotsgameht.domain.AppGameProp; import com.yz.slotsgameht.domain.AppProbabilitySetting; import com.yz.slotsgameht.service.AppGamePropService; import com.yz.slotsgameht.utils.GetIpAddress; import com.yz.slotsgameht.utils.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.List; /** * @Author: Lukizzz * @Date: 2018/8/31 11:45 * @Description: */ @RestController @RequestMapping(value = "/prop") public class AppGamePropController { private final Logger log = LoggerFactory.getLogger(AppProbabilitySetting.class); @Autowired private AppGamePropService appGamePropService; @RequestMapping(value ="/findPropList" ) public List<AppGameProp> findPropList(){ return appGamePropService.findPropList(); } @RequestMapping(value = "editNameSave") public Result editNameSave(Long id, String name, HttpServletRequest request){ String ip = GetIpAddress.getIpAddress(request); log.info("修改名称的id: {},新名称: {},本地ip地址:{}", id, name, ip); appGamePropService.editNameSave(id, name); return new Result(); } @RequestMapping(value = "editGoldNumSave") public Result editGoldNumSave(Long id, Integer goldNum,HttpServletRequest request){ String ip = GetIpAddress.getIpAddress(request); log.info("修改兑换金币的id: {},新兑换金币数量: {},本地ip地址:{}", id, goldNum, ip); appGamePropService.editGoldNumSave(id, goldNum); return new Result(); } }
上面的代码中有一点需要注意:datagrid传输的数据是json,因为这边还有一个查找的功能,所以在控制层需要加上@responsebody注解或是将@controller注解变成@restcontroller,里面也包含了@responsebody的注解
业务逻辑层:
package com.yz.slotsgameht.service; import com.yz.slotsgameht.dao.AppGamePropDAO; import com.yz.slotsgameht.domain.AppGameProp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @Author: Lukizzz * @Date: 2018/8/31 11:48 * @Description: */ @Service public class AppGamePropService { @Autowired private AppGamePropDAO appGamePropDAO; public List<AppGameProp> findPropList(){ return appGamePropDAO.findAll(); } public void editNameSave(Long id,String name){ appGamePropDAO.updateNameById(id,name); } public void editGoldNumSave(Long id,Integer goldNum){ appGamePropDAO.updateGoldNumById(id,goldNum); } }
数据访问层:
package com.yz.slotsgameht.dao; import com.yz.slotsgameht.domain.AppGameProp; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; /** * @Author: Lukizzz * @Date: 2018/8/31 11:48 * @Description: */ public interface AppGamePropDAO extends JpaRepository<AppGameProp,Long> { /** * 修改道具名称 * @param id * @param name */ @Transactional(rollbackFor = Exception.class) @Modifying @Query(value = "update app_game_prop u set u.name = :name where u.id = :id", nativeQuery = true) void updateNameById(@Param(value = "id") Long id, @Param(value = "name") String name); /** * 修改兑换金币 * @param id * @param goldNum */ @Transactional(rollbackFor = Exception.class) @Modifying @Query(value = "update app_game_prop set gold_num = :goldNum where id = :id", nativeQuery = true) void updateGoldNumById(@Param(value = "id") Long id, @Param(value = "goldNum") Integer goldNum); }
这边也需要注意一点是:因为功能是修改update,所以不需要返回数据,在service层和DAO都使用void
附上这个功能ftl的代码和相关截图:
<!DOCTYPE html> <html> <head> <#include "inc/inc.ftl"/> </head> <body> <div class="easyui-layout" data-options="fit:true,border:false"> <table id="dg"></table> </div> <div id="toolbar" style="padding:5px;height:auto"> <div> <a οnclick="editName();" href="javascript:void(0);" class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-edit'">修改道具名称</a> <a οnclick="editGoldNum();" href="javascript:void(0);" class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-edit'">修改兑换金币数</a> </div> </div> <div id="dlg_edit" class="easyui-dialog" style="width:400px;height:auto;padding:10px 20px" buttons="#dlg-buttons_edit1" data-options="closed:true,modal:true"> <form id="fm_edit" method="post" enctype="multipart/form-data"> <input type="hidden" id="id1" name="id"/> 请输入新名称: <input class="easyui-textbox" data-options="prompt:'请输入新的道具名称'" style="width:50%;height:32px" name="name"> </form> </div> <div id="dlg-buttons_edit1"> <a href="javascript:void(0)" class="easyui-linkbutton c8" data-options="iconCls:'icon-ok'" onclick="javascript:editNameSave();" style="width:90px;">保存</a> <a href="javascript:void(0)" class="easyui-linkbutton c2" data-options="iconCls:'icon-cancel'" onclick="javascript:$('#dlg_edit').dialog('close');" style="width:90px;">取消</a> </div> <div id="dlg_editNum" class="easyui-dialog" style="width:400px;height:auto;padding:10px 20px" buttons="#dlg-buttons_edit2" data-options="closed:true,modal:true"> <form id="fm_editNum" method="post" enctype="multipart/form-data"> <input type="hidden" id="id2" name="id"/> 请输入兑换金币数: <input class="easyui-textbox" data-options="prompt:'请输入兑换金币数'" style="width:50%;height:32px" name="goldNum"> </form> </div> <div id="dlg-buttons_edit2"> <a href="javascript:void(0)" class="easyui-linkbutton c8" data-options="iconCls:'icon-ok'" onclick="javascript:editGoldNumSave();" style="width:90px;">保存</a> <a href="javascript:void(0)" class="easyui-linkbutton c2" data-options="iconCls:'icon-cancel'" onclick="javascript:$('#dlg_editNum').dialog('close');" style="width:90px;">取消</a> </div> </body> </html> <script type="text/javascript"> $(document).ready(function () { loadData(); }); function loadData() { $("#dg").datagrid({ url: '${request.contextPath}/prop/findPropList', striped: true, border: false, collapsible: false, //是否可折叠的 loadMsg: '正在加载数据...', idField: 'id', fit: true, //自动大小 singleSelect: true,//是否单选 pagination: true,//分页控件 pageSize: 20, columns: [[{ field: 'name', title: '道具名称', width: 150, align: 'center' }, { field: 'goldNum', title: '兑换金币数', width: 150, align: 'center' }, { field: 'propType', title: '所属元素', width: 150, align: 'center' }]], toolbar: '#toolbar' }); } function editName() { var row = $('#dg').datagrid('getSelected'); if (row) { $('#fm_edit').form('load', row); $('#dlg_edit').dialog('open').dialog('setTitle', '修改'); } else { $.messager.alert("提示", "请选择一条记录"); } } function editNameSave() { $('#fm_edit').form('submit', { url: "${request.contextPath}/prop/editNameSave", success: function (result) { var result = eval('(' + result + ')'); if (result.code == 0) { $('#dg').datagrid('reload'); $('#dlg_edit').dialog('close'); } else { $.messager.show({ title: '提示', msg: result.message }); } } }); } function editGoldNum() { var row = $('#dg').datagrid('getSelected'); if (row) { $('#fm_editNum').form('load', row); $('#dlg_editNum').dialog('open').dialog('setTitle', '修改'); } else { $.messager.alert("提示", "请选择一条记录"); } } function editGoldNumSave() { $('#fm_editNum').form('submit', { url: "${request.contextPath}/prop/editGoldNumSave", success: function (result) { var result = eval('(' + result + ')'); if (result.code == 0) { $('#dg').datagrid('reload'); $('#dlg_editNum').dialog('close'); } else { $.messager.show({ title: '提示', msg: result.message }); } } }); } </script>
在日志配置的时候,要添加一个配置文件
网上应该有很多:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration> <configuration scan="true"> <include resource="org/springframework/boot/logging/logback/base.xml"/> <!-- The FILE and ASYNC appenders are here as examples for a production configuration --> <property name="PROJECT" value="hnuser" /> <property name="ROOT" value="logs/" /> <property name="FILESIZE" value="10MB" /> <property name="MAXHISTORY" value="3" /> <timestamp key="DATETIME" datePattern="yyyy-MM-dd HH:mm:ss" /> <!-- ERROR 输入到文件,按日期和文件大小 --> <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder charset="utf-8"> <Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${ROOT}%d/error.%i.log</fileNamePattern> <maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>${FILESIZE}</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- WARN 输入到文件,按日期和文件大小 --> <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder charset="utf-8"> <Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>WARN</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${ROOT}%d/warn.%i.log</fileNamePattern> <maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>${FILESIZE}</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- INFO 输入到文件,按日期和文件大小 --> <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder charset="utf-8"> <Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${ROOT}%d/info.%i.log</fileNamePattern> <maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>${FILESIZE}</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- DEBUG 输入到文件,按日期和文件大小 --> <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder charset="utf-8"> <Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${ROOT}%d/debug.%i.log</fileNamePattern> <maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>${FILESIZE}</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- Logger 根目录 --> <root level="INFO"> <appender-ref ref="DEBUG" /> <appender-ref ref="ERROR" /> <appender-ref ref="WARN" /> <appender-ref ref="INFO" /> </root> <logger name="javax.activation" level="WARN"/> <logger name="javax.mail" level="WARN"/> <logger name="javax.management.remote" level="WARN"/> <logger name="javax.xml.bind" level="WARN"/> <logger name="ch.qos.logback" level="WARN"/> <logger name="com.codahale.metrics" level="WARN"/> <logger name="com.netflix" level="WARN"/> <logger name="com.netflix.discovery" level="INFO"/> <logger name="com.ryantenney" level="WARN"/> <logger name="com.sun" level="WARN"/> <logger name="com.zaxxer" level="WARN"/> <logger name="io.undertow" level="WARN"/> <logger name="io.undertow.websockets.jsr" level="ERROR"/> <logger name="org.ehcache" level="WARN"/> <logger name="org.apache" level="WARN"/> <logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/> <logger name="org.bson" level="WARN"/> <logger name="org.hibernate.validator" level="WARN"/> <logger name="org.hibernate" level="WARN"/> <logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/> <logger name="org.springframework" level="WARN"/> <logger name="org.springframework.web" level="WARN"/> <logger name="org.springframework.security" level="WARN"/> <logger name="org.springframework.cache" level="WARN"/> <logger name="org.thymeleaf" level="WARN"/> <logger name="org.xnio" level="WARN"/> <logger name="springfox" level="WARN"/> <logger name="sun.rmi" level="WARN"/> <logger name="liquibase" level="WARN"/> <logger name="LiquibaseSchemaResolver" level="INFO"/> <logger name="sun.net.www" level="INFO"/> <logger name="sun.rmi.transport" level="WARN"/> <!-- https://logback.qos.ch/manual/configuration.html#shutdownHook and https://jira.qos.ch/browse/LOGBACK-1090 --> <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/> <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> <resetJUL>true</resetJUL> </contextListener> </configuration>
也别忘了在控制层引入
private final Logger log = LoggerFactory.getLogger(SysUser.class);