diff --git a/src/main/java/com/rymcu/vertical/core/service/LogService.java b/src/main/java/com/rymcu/vertical/core/service/LogService.java deleted file mode 100644 index cb15af0..0000000 --- a/src/main/java/com/rymcu/vertical/core/service/LogService.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.rymcu.vertical.core.service; - - - -/** - * 体检者日志接口 - */ -public interface LogService { - - //void log(LogInfo logInfo); - -} diff --git a/src/main/java/com/rymcu/vertical/core/service/log/VisitAspect.java b/src/main/java/com/rymcu/vertical/core/service/log/VisitAspect.java new file mode 100644 index 0000000..c3f0986 --- /dev/null +++ b/src/main/java/com/rymcu/vertical/core/service/log/VisitAspect.java @@ -0,0 +1,104 @@ +package com.rymcu.vertical.core.service.log; + +import com.rymcu.vertical.core.service.log.constant.LoggerConstant; +import com.rymcu.vertical.dto.TokenUser; +import com.rymcu.vertical.entity.Visit; +import com.rymcu.vertical.jwt.def.JwtConstants; +import com.rymcu.vertical.service.ArticleService; +import com.rymcu.vertical.service.VisitService; +import com.rymcu.vertical.util.UserUtils; +import com.rymcu.vertical.util.Utils; +import com.rymcu.vertical.web.api.exception.BaseApiException; +import com.rymcu.vertical.web.api.exception.ErrorCode; +import org.apache.commons.lang.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.HandlerMapping; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * 浏览 + * @author ronger + */ +@Aspect +@Component +public class VisitAspect { + + @Resource + private ArticleService articleService; + @Resource + private VisitService visitService; + + @Pointcut("@annotation(com.rymcu.vertical.core.service.log.annotation.VisitLogger)") + public void pointCut() {} + + /** + * 保存系统操作日志 + * + * @param joinPoint 连接点 + * @return 方法执行结果 + * @throws Throwable 调用出错 + */ + @AfterReturning(value = "pointCut()", returning="obj") + public void save(JoinPoint joinPoint, Object obj) { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + String ip = Utils.getIpAddress(request); + String url = request.getRequestURL().toString(); + String ua = request.getHeader("user-agent"); + String referer = request.getHeader("Referer"); + String methodName = joinPoint.getSignature().getName(); + Map params = getParams(request); + if (params.isEmpty()) { + params = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + } else { + params.putAll((Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE)); + } + switch (methodName) { + case LoggerConstant.ARTICLE: + Integer id = Integer.parseInt(String.valueOf(params.get("id"))); + articleService.incrementArticleViewCount(id); + break; + default: + break; + } + Visit visit = new Visit(); + visit.setVisitUrl(url); + visit.setVisitIp(ip); + visit.setVisitUa(ua); + visit.setVisitCity(""); + visit.setVisitDeviceId(""); + visit.setVisitRefererUrl(referer); + visit.setCreatedTime(new Date()); + String authHeader = request.getHeader(JwtConstants.AUTHORIZATION); + if(StringUtils.isNotBlank(authHeader)){ + TokenUser tokenUser = UserUtils.getTokenUser(authHeader); + visit.setVisitUserId(tokenUser.getIdUser()); + } + visitService.save(visit); + } + + private Map getParams(HttpServletRequest request) { + Map paramsMap = new HashMap<>(10); + Enumeration paraNames = request.getParameterNames(); + while (paraNames.hasMoreElements()) { + String key = paraNames.nextElement(); + if ("password".equals(key)) { + continue; + } + paramsMap.put(key, request.getParameter(key)); + } + return paramsMap; + } +} diff --git a/src/main/java/com/rymcu/vertical/core/service/log/annotation/VisitLogger.java b/src/main/java/com/rymcu/vertical/core/service/log/annotation/VisitLogger.java new file mode 100644 index 0000000..b0c746c --- /dev/null +++ b/src/main/java/com/rymcu/vertical/core/service/log/annotation/VisitLogger.java @@ -0,0 +1,12 @@ +package com.rymcu.vertical.core.service.log.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * 浏览记录器 + * @author ronger + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface VisitLogger { +} diff --git a/src/main/java/com/rymcu/vertical/core/service/log/constant/LoggerConstant.java b/src/main/java/com/rymcu/vertical/core/service/log/constant/LoggerConstant.java new file mode 100644 index 0000000..5905a5b --- /dev/null +++ b/src/main/java/com/rymcu/vertical/core/service/log/constant/LoggerConstant.java @@ -0,0 +1,12 @@ +package com.rymcu.vertical.core.service.log.constant; + +/** + * @author ronger + */ +public class LoggerConstant { + + public final static String ARTICLE = "article"; + + public final static String ARTICLES = "articles"; + +} diff --git a/src/main/java/com/rymcu/vertical/entity/Visit.java b/src/main/java/com/rymcu/vertical/entity/Visit.java new file mode 100644 index 0000000..d62c1ea --- /dev/null +++ b/src/main/java/com/rymcu/vertical/entity/Visit.java @@ -0,0 +1,42 @@ +package com.rymcu.vertical.entity; + +import lombok.Data; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Date; + +/** + * 浏览表 + * @author ronger + */ +@Data +@Table(name="vertical_visit") +public class Visit implements Serializable,Cloneable { + + /** 主键 */ + @Id + @GeneratedValue(generator = "JDBC") + private Integer id; + /** 浏览链接 */ + private String visitUrl; + /** IP */ + private String visitIp; + /** User-Agent */ + private String visitUa; + /** 城市 */ + private String visitCity; + /** 设备唯一标识 */ + private String visitDeviceId; + /** 浏览者 id */ + private Integer visitUserId; + /** 上游链接 */ + private String visitRefererUrl; + /** 创建时间 */ + private Date createdTime; + /** 过期时间 */ + private Date expiredTime; + +} diff --git a/src/main/java/com/rymcu/vertical/mapper/ArticleMapper.java b/src/main/java/com/rymcu/vertical/mapper/ArticleMapper.java index ae9c19d..71b036c 100644 --- a/src/main/java/com/rymcu/vertical/mapper/ArticleMapper.java +++ b/src/main/java/com/rymcu/vertical/mapper/ArticleMapper.java @@ -32,4 +32,12 @@ public interface ArticleMapper extends Mapper
{ Integer deleteTagArticle(@Param("id") Integer id); List selectTags(@Param("idArticle") Integer idArticle); + + /** + * + * @param id + * @param articleViewCount + * @return + */ + Integer updateArticleViewCount(@Param("id") Integer id, @Param("articleViewCount") Integer articleViewCount); } diff --git a/src/main/java/com/rymcu/vertical/mapper/VisitMapper.java b/src/main/java/com/rymcu/vertical/mapper/VisitMapper.java new file mode 100644 index 0000000..0a2bba6 --- /dev/null +++ b/src/main/java/com/rymcu/vertical/mapper/VisitMapper.java @@ -0,0 +1,10 @@ +package com.rymcu.vertical.mapper; + +import com.rymcu.vertical.core.mapper.Mapper; +import com.rymcu.vertical.entity.Visit; + +/** + * @author ronger + */ +public interface VisitMapper extends Mapper { +} diff --git a/src/main/java/com/rymcu/vertical/service/ArticleService.java b/src/main/java/com/rymcu/vertical/service/ArticleService.java index 91e87c2..a901362 100644 --- a/src/main/java/com/rymcu/vertical/service/ArticleService.java +++ b/src/main/java/com/rymcu/vertical/service/ArticleService.java @@ -68,4 +68,10 @@ public interface ArticleService extends Service
{ * @return * */ Map delete(Integer id); + + /** + * 增量文章浏览数 + * @param id + */ + void incrementArticleViewCount(Integer id); } diff --git a/src/main/java/com/rymcu/vertical/service/VisitService.java b/src/main/java/com/rymcu/vertical/service/VisitService.java new file mode 100644 index 0000000..05b2327 --- /dev/null +++ b/src/main/java/com/rymcu/vertical/service/VisitService.java @@ -0,0 +1,10 @@ +package com.rymcu.vertical.service; + +import com.rymcu.vertical.core.service.Service; +import com.rymcu.vertical.entity.Visit; + +/** + * @author ronger + */ +public interface VisitService extends Service { +} diff --git a/src/main/java/com/rymcu/vertical/service/impl/ArticleServiceImpl.java b/src/main/java/com/rymcu/vertical/service/impl/ArticleServiceImpl.java index d60f618..a963a89 100644 --- a/src/main/java/com/rymcu/vertical/service/impl/ArticleServiceImpl.java +++ b/src/main/java/com/rymcu/vertical/service/impl/ArticleServiceImpl.java @@ -154,6 +154,14 @@ public class ArticleServiceImpl extends AbstractService
implements Arti return map; } + @Override + @Transactional(rollbackFor = Exception.class) + public void incrementArticleViewCount(Integer id) { + Article article = articleMapper.selectByPrimaryKey(id); + Integer articleViewCount = article.getArticleViewCount() + 1; + articleMapper.updateArticleViewCount(article.getIdArticle(), articleViewCount); + } + private ArticleDTO genArticle(ArticleDTO article,Integer type) { Author author = articleMapper.selectAuthor(article.getArticleAuthorId()); article.setArticleAuthor(author); diff --git a/src/main/java/com/rymcu/vertical/service/impl/VisitServiceImpl.java b/src/main/java/com/rymcu/vertical/service/impl/VisitServiceImpl.java new file mode 100644 index 0000000..5ecb0f6 --- /dev/null +++ b/src/main/java/com/rymcu/vertical/service/impl/VisitServiceImpl.java @@ -0,0 +1,13 @@ +package com.rymcu.vertical.service.impl; + +import com.rymcu.vertical.core.service.AbstractService; +import com.rymcu.vertical.entity.Visit; +import com.rymcu.vertical.service.VisitService; +import org.springframework.stereotype.Service; + +/** + * @author ronger + */ +@Service +public class VisitServiceImpl extends AbstractService implements VisitService { +} diff --git a/src/main/java/com/rymcu/vertical/util/Utils.java b/src/main/java/com/rymcu/vertical/util/Utils.java index 635098e..c4b6983 100644 --- a/src/main/java/com/rymcu/vertical/util/Utils.java +++ b/src/main/java/com/rymcu/vertical/util/Utils.java @@ -10,6 +10,7 @@ import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.springframework.core.env.Environment; +import javax.servlet.http.HttpServletRequest; import java.time.*; import java.util.Date; import java.util.HashMap; @@ -20,6 +21,7 @@ import java.util.Map; */ public class Utils { public static final String HASH_ALGORITHM = "SHA-1"; + public static final String UNKOWN = "unknown"; public static final int HASH_INTERATIONS = 1024; public static final int SALT_SIZE = 8; @@ -155,4 +157,29 @@ public class Utils { map.put("pagination", pagination); return map; } + + public static String getIpAddress(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || UNKOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || UNKOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || UNKOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || UNKOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || UNKOWN.equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + // 如果是多级代理,那么取第一个ip为客户端ip + if (ip != null && ip.indexOf(",") != -1) { + ip = ip.substring(0, ip.indexOf(",")).trim(); + } + + return ip; + } } diff --git a/src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java b/src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java index 3331d8a..631e1c5 100644 --- a/src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java +++ b/src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java @@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; +import java.util.HashMap; import java.util.Map; /** @@ -22,6 +23,16 @@ public class ArticleController { @Resource private ArticleService articleService; + + + @GetMapping("/detail/{id}") + public GlobalResult> detail(@PathVariable Integer id){ + ArticleDTO articleDTO = articleService.findArticleDTOById(id,2); + Map map = new HashMap<>(1); + map.put("article", articleDTO); + return GlobalResultGenerator.genSuccessResult(map); + } + @PostMapping("/post") public GlobalResult postArticle(@RequestBody ArticleDTO article, HttpServletRequest request) throws BaseApiException, UnsupportedEncodingException { Map map = articleService.postArticle(article,request); diff --git a/src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java b/src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java index 9917ebe..789481e 100644 --- a/src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java +++ b/src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java @@ -5,6 +5,7 @@ import com.github.pagehelper.PageInfo; import com.rymcu.vertical.core.result.GlobalResult; import com.rymcu.vertical.core.result.GlobalResultGenerator; import com.rymcu.vertical.core.result.GlobalResultMessage; +import com.rymcu.vertical.core.service.log.annotation.VisitLogger; import com.rymcu.vertical.dto.ArticleDTO; import com.rymcu.vertical.dto.ForgetPasswordDTO; import com.rymcu.vertical.dto.TokenUser; @@ -89,6 +90,7 @@ public class CommonApiController { } @GetMapping("/articles") + @VisitLogger public GlobalResult articles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows, @RequestParam(defaultValue = "") String searchText, @RequestParam(defaultValue = "") String tag){ PageHelper.startPage(page, rows); List list = articleService.findArticles(searchText,tag); @@ -98,21 +100,14 @@ public class CommonApiController { } @GetMapping("/article/{id}") - public GlobalResult> detail(@PathVariable Integer id){ + @VisitLogger + public GlobalResult> article(@PathVariable Integer id){ ArticleDTO articleDTO = articleService.findArticleDTOById(id,1); Map map = new HashMap<>(1); map.put("article", articleDTO); return GlobalResultGenerator.genSuccessResult(map); } - @GetMapping("/update/{id}") - public GlobalResult> update(@PathVariable Integer id){ - ArticleDTO articleDTO = articleService.findArticleDTOById(id,2); - Map map = new HashMap<>(1); - map.put("article", articleDTO); - return GlobalResultGenerator.genSuccessResult(map); - } - @GetMapping("/token/{token}") public GlobalResult token(@PathVariable String token){ TokenUser tokenUser = UserUtils.getTokenUser(token); diff --git a/src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java b/src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java index a67ff64..beed345 100644 --- a/src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java +++ b/src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java @@ -4,6 +4,7 @@ import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.rymcu.vertical.core.result.GlobalResult; import com.rymcu.vertical.core.result.GlobalResultGenerator; +import com.rymcu.vertical.core.service.log.annotation.VisitLogger; import com.rymcu.vertical.dto.ArticleDTO; import com.rymcu.vertical.entity.Topic; import com.rymcu.vertical.service.ArticleService; @@ -33,6 +34,7 @@ public class TopicController { } @GetMapping("/{name}") + @VisitLogger public GlobalResult articles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows, @PathVariable String name){ PageHelper.startPage(page, rows); List list = articleService.findArticlesByTopicUri(name); diff --git a/src/main/java/mapper/ArticleMapper.xml b/src/main/java/mapper/ArticleMapper.xml index 9376b97..65d0423 100644 --- a/src/main/java/mapper/ArticleMapper.xml +++ b/src/main/java/mapper/ArticleMapper.xml @@ -63,6 +63,9 @@ update vertical_article_content set article_content = #{articleContent},article_content_html = #{articleContentHtml},updated_time = sysdate() where id_article = #{idArticle} + + update vertical_article set article_view_count = #{articleViewCount} where id = #{id} + delete from vertical_tag_article where id_article = #{id} diff --git a/src/main/java/mapper/VisitMapper.xml b/src/main/java/mapper/VisitMapper.xml new file mode 100644 index 0000000..d912756 --- /dev/null +++ b/src/main/java/mapper/VisitMapper.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/static/vertical.pdman.json b/src/main/resources/static/vertical.pdman.json index 72d2044..d88e481 100644 --- a/src/main/resources/static/vertical.pdman.json +++ b/src/main/resources/static/vertical.pdman.json @@ -98,16 +98,6 @@ "autoIncrement": false, "defaultValue": "" }, - { - "name": "time_ago", - "type": "VARCHAR_32", - "chnname": "过去时长", - "remark": "", - "pk": false, - "notNull": false, - "autoIncrement": false, - "defaultValue": "" - }, { "name": "article_permalink", "type": "VARCHAR_128", @@ -1486,6 +1476,122 @@ } ], "chnname": "关注表" + }, + { + "title": "vertical_visit", + "fields": [ + { + "name": "id", + "type": "BigInt", + "remark": "", + "chnname": "主键", + "pk": true, + "notNull": true, + "autoIncrement": true + }, + { + "name": "visit_url", + "type": "VARCHAR_256", + "remark": "", + "chnname": "浏览链接" + }, + { + "name": "visit_ip", + "type": "ShortString", + "remark": "", + "chnname": "IP" + }, + { + "name": "visit_ua", + "type": "VARCHAR_256", + "remark": "", + "chnname": "User-Agent" + }, + { + "name": "visit_city", + "type": "IdOrKey", + "remark": "", + "chnname": "城市" + }, + { + "name": "visit_device_id", + "type": "VARCHAR_256", + "remark": "", + "chnname": "设备唯一标识" + }, + { + "name": "visit_user_id", + "type": "BigInt", + "remark": "", + "chnname": "浏览者 id" + }, + { + "name": "visit_referer_url", + "type": "VARCHAR_256", + "remark": "", + "chnname": "上游链接" + }, + { + "name": "created_time", + "type": "DateTime", + "remark": "", + "chnname": "创建时间" + }, + { + "name": "expired_time", + "type": "DateTime", + "remark": "", + "chnname": "过期时间" + } + ], + "indexs": [], + "headers": [ + { + "fieldName": "chnname", + "relationNoShow": false + }, + { + "fieldName": "name", + "relationNoShow": false + }, + { + "fieldName": "type", + "relationNoShow": false + }, + { + "fieldName": "dataType", + "relationNoShow": true + }, + { + "fieldName": "remark", + "relationNoShow": true + }, + { + "fieldName": "pk", + "relationNoShow": false + }, + { + "fieldName": "notNull", + "relationNoShow": true + }, + { + "fieldName": "autoIncrement", + "relationNoShow": true + }, + { + "fieldName": "defaultValue", + "relationNoShow": true + }, + { + "fieldName": "relationNoShow", + "relationNoShow": true + }, + { + "fieldName": "uiHint", + "relationNoShow": true + } + ], + "chnname": "浏览表" } ], "graphCanvas": {