一、写在前面,需要注意的几点
1.@JsonSerialize注解
此注解用于属性或者getter方法上,用于在序列化时嵌入开发者自定义的代码。
使用时先 自定义日期序列化类,比如CustomDateTimeSerializer ,然后再在实体的get方法上加上@JsonSerialize(using = CustomDateTimeSerializer .class)
2.对象级联
大致是这意思:比如日志实体里面还有个对象类型的user属性
然后前台搜索框中输入的用户名是Log对象(实体)里面的User对象中的一个属性trueName:
function formatUser(val,row){
return val.trueName+" ("+val.userName+") ";}function searchLog(){
$("#dg").datagrid('load',{
"type":$("#s_type").combobox("getValue"),"user.trueName":$("s_trueName").val(),"btime":$("#s_btime").datetimebox("getValue"),'etime':$("#s_etime").datetimebox("getValue")});}
然后service实现类中有这样一个条件:
3.Controller中加上initBinder方法,完成指定日期格式参数绑定
4.datetimebox获取时间
$("#s_btime").datetimebox(“getValue”)
5.@Temporal注解
原文链接:
https://www.cnblogs.com/meng-ma-blogs/p/8474175.html
数据库的字段类型有date、time、datetime
而Temporal注解的作用就是帮Java的Date类型进行格式化,一共有三种注解值:
第一种:@Temporal(TemporalType.DATE)——>实体类会封装成日期“yyyy-MM-dd”的 Date类型。
第二种:@Temporal(TemporalType.TIME)——>实体类会封装成时间“hh-MM-ss”的 Date类型。
第三种:@Temporal(TemporalType.TIMESTAMP)——>实体类会封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型。
注解方式有两种:
写在字段上:
@Temporal(TemporalType.TIMESTAMP)private Date birthday;
写在 getXxx方法上:
@Temporal(TemporalType.DATE)@Column(name = "birthday", length = 10)public Date getBirthday() {
return this.birthday;}
二、日志实体和表
表数据:
实体:
/*** 日志实体* @author Administrator**/
@Entity
@Table(name="t_log")
public class Log {
public final static String LOGIN_ACTION="登录操作";public final static String LOGOUT_ACTION="注销操作";public final static String SEARCH_ACTION="查询操作";public final static String UPDATE_ACTION="更新操作";public final static String ADD_ACTION="添加操作";public final static String DELETE_ACTION="删除操作";@Id@GeneratedValueprivate Integer id; // 编号@Column(length=100)private String type; // 日志类型@ManyToOne@JoinColumn(name="userId")private User user; // 操作用户@Column(length=1000)private String content; // 操作内容@Temporal(TemporalType.TIMESTAMP) //对Date类型进行格式化private Date time; // 操作日期时间 封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型。@Transientprivate Date btime; // 起始时间 搜索用到 如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,public Date getBtime() {
return btime;}@Transientprivate Date etime; // 结束时间 搜索用到 如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient, public void setBtime(Date btime) {
this.btime = btime;}public Date getEtime() {
return etime;}public void setEtime(Date etime) {
this.etime = etime;}public Log() {
super();} public Log(String type, String content) {
super();this.type = type;this.content = content;}public Integer getId() {
return id;}public void setId(Integer id) {
this.id = id;}public String getType() {
return type;}public void setType(String type) {
this.type = type;}public User getUser() {
return user;}public void setUser(User user) {
this.user = user;}public String getContent() {
return content;}public void setContent(String content) {
this.content = content;} @JsonSerialize(using=CustomDateTimeSerializer.class) //自定义日期序列化类public Date getTime() {
return time;}public void setTime(Date time) {
this.time = time;}
}
/*** 自定义返回JSON 数据格式中日期格式化处理*/
public class CustomDateTimeSerializer extends JsonSerializer<Date>{
@Overridepublic void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)throws IOException, JsonProcessingException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); gen.writeString(sdf.format(value)); }}
三.日志保存 大致流程
1.比如用户 进行登录 操作
在登录成功后调用logService,保存登录这条日志:
logService.save(new Log(Log.LOGIN_ACTION,"用户登录"));
2.比如用户添加或者修改了用户信息,当然要将这日志保存起来
/*** 添加或者修改用户信息* @param user* @return* @throws Exception*/@ResponseBody @RequestMapping("/save")public Map<String,Object> save(User user) throws Exception{
Map<String,Object> resultMap=new HashMap<>();if(user.getId()==null) {
if(userService.findByUserName(user.getUserName())!=null) {
resultMap.put("success", false);resultMap.put("errorInfo", "用户名已存在!");return resultMap;}}if(user.getId()!=null) {
logService.save(new Log(Log.UPDATE_ACTION,"更新用户信息:"+user));}else {
logService.save(new Log(Log.ADD_ACTION,"添加用户:"+user));}userService.save(user);resultMap.put("success", true);return resultMap;}
四、日志后台管理 分页、多条件查询
1.页面easyui和js代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>系统日志</title>
<link rel="stylesheet" type="text/css" href="/static/jquery-easyui-1.3.3/themes/default/easyui.css"></link>
<link rel="stylesheet" type="text/css" href="/static/jquery-easyui-1.3.3/themes/icon.css"></link>
<script type="text/javascript" src="/static/jquery-easyui-1.3.3/jquery.min.js"></script>
<script type="text/javascript" src="/static/jquery-easyui-1.3.3/jquery.easyui.min.js"></script>
<script type="text/javascript" src="/static/jquery-easyui-1.3.3/locale/easyui-lang-zh_CN.js"></script><script type="text/javascript">function formatUser(val,row){
return val.trueName+" ("+val.userName+") ";}//多条件搜索框function searchLog(){
$("#dg").datagrid('load',{
"type":$("#s_type").combobox("getValue"),"user.trueName":$("s_trueName").val(),"btime":$("#s_btime").datetimebox("getValue"),'etime':$("#s_etime").datetimebox("getValue")});}//重置输入框function resetValue(){
$("#s_type").combobox("setValue","");$("#s_trueName").val("");$("#s_btime").datetimebox("setValue","");$("#s_etime").datetimebox("setValue","");}
</script></head>
<body style="margin: 1px"><table id="dg" title="系统日志" class="easyui-datagrid"fitColumns="true" pagination="true" rownumbers="true" singleSelect="true"url="/admin/log/list" fit="true" toolbar="#tb"><thead><th field="id" width="20" align="center">编号</th><th field="type" width="30" align="center">日志类型</th><th field="user" width="50" align="center" formatter="formatUser">操作用户</th><th field="time" width="50" align="center">操作时间</th><th field="content" width="250" align="left">操作内容</th></thead></table><div id="tb"><fieldset style="border-color: #E7F0FF"><legend>查询设置</legend> 查询设置 <select class="easyui-combobox" id="s_type" style="width: 154px" editable="false" panelHeight="auto"><option value="">所有类型</option><option value="登录操作">登录操作</option><option value="注销操作">注销操作</option><option value="查询操作">查询操作</option><option value="更新操作">更新操作</option><option value="添加操作">添加操作</option><option value="删除操作">删除操作</option></select> 操作用户: <input type="text" id="s_trueName" size="20" onkeydown="if(event.keyCode==13) searchLog()"/> 操作时间: <input id="s_btime" class="easyui-datetimebox" editable=false style="width:150px"/> - <input id="s_etime" class="easyui-datetimebox" editable=false style="width:150px"/> <a href="javascript:searchLog()" class="easyui-linkbutton" iconCls="icon-search" plain="true">搜索</a> <a href="javascript:resetValue()" class="easyui-linkbutton" iconCls="icon-reset" plain="true">重置</a></fieldset></div>
</body>
</html>
- Controller层
/*** 后台管理用户Controller* @author Administrator**/
@RestController
@RequestMapping("/admin/log")
public class LogAdminController {
@Resourceprivate LogService logService;@InitBinderpublic void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");dateFormat.setLenient(true);binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); //true:允许输入空值,false:不能为空值}/*** 根据条件分页查询日志信息* @param log* @param page* @param rows* @return* @throws Exception*/@RequestMapping("/list")@RequiresPermissions(value="系统日志") //当前用户必须拥有 此权限才能访问此方法public Map<String,Object> list(Log log,@RequestParam(value="page",required=false)Integer page,@RequestParam(value="rows",required=false)Integer rows)throws Exception{
Map<String,Object> resultMap=new HashMap<>();List<Log> logList=logService.list(log, page, rows, Direction.DESC, "time");Long total=logService.getCount(log);resultMap.put("rows", logList);resultMap.put("total", total);return resultMap;}}
3.Service实现类
@Service("logService")
public class LogServiceImpl implements LogService{
@Resourceprivate LogRepository logRepository;@Resourceprivate UserRepository userRepository;@Overridepublic void save(Log log) {
log.setTime(new Date()); //设置操作日期//设置当前用户log.setUser(userRepository.findByUserName((String) SecurityUtils.getSubject().getPrincipal()));logRepository.save(log);}/*** 根据条件分页查询日志信息* @param log* @param page* @param pageSize* @param direction* @param properties* @return*/@Overridepublic List<Log> list(Log log, Integer page, Integer pageSize, Direction direction, String... properties) {
Pageable pageable=new PageRequest(page-1,pageSize,direction,properties);//查询所需参数pageablePage<Log> pageLog=logRepository.findAll(new Specification<Log>() {
@Overridepublic Predicate toPredicate(Root<Log> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate=cb.conjunction();//存储下面构造的查询条件if(log!=null) {
if(StringUtil.isNotEmpty(log.getType())) {
predicate.getExpressions().add(cb.like(root.get("type"), log.getType()));}if(log.getUser()!=null && StringUtil.isNotEmpty(log.getUser().getTrueName())) {
predicate.getExpressions().add(cb.like(root.get("user").get("trueName"), "%"+log.getUser().getTrueName()+"%"));}if(log.getBtime()!=null) {
predicate.getExpressions().add(cb.greaterThanOrEqualTo(root.get("time"), log.getBtime()));}if(log.getEtime()!=null) {
predicate.getExpressions().add(cb.lessThanOrEqualTo(root.get("time"), log.getEtime()));}}return predicate;}}, pageable); return pageLog.getContent();}/*** 获取总记录数* @param log* @return*/@Overridepublic Long getCount(Log log) {
Long count=logRepository.count(new Specification<Log>() {
@Overridepublic Predicate toPredicate(Root<Log> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate=cb.conjunction();//存储下面构造的查询条件if(log!=null) {
if(StringUtil.isNotEmpty(log.getType())) {
predicate.getExpressions().add(cb.like(root.get("type"), log.getType()));}if(log.getUser()!=null && StringUtil.isNotEmpty(log.getUser().getTrueName())) {
predicate.getExpressions().add(cb.like(root.get("user").get("trueName"), "%"+log.getUser().getTrueName()+"%"));}if(log.getBtime()!=null) {
predicate.getExpressions().add(cb.greaterThanOrEqualTo(root.get("time"), log.getBtime()));}if(log.getEtime()!=null) {
predicate.getExpressions().add(cb.lessThanOrEqualTo(root.get("time"), log.getEtime()));}}return predicate;}});return count;}}
完整代码地址:
https://gitee.com/never_enough/jxc_system/tree/master