Skip to content

Commit d9cf115

Browse files
committed
implemented exclusion search-robots from visit counting by storing robots' names into table SeoRobotAgent
1 parent aab828c commit d9cf115

14 files changed

Lines changed: 284 additions & 11 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ apply plugin: 'spring-boot'
77
sourceCompatibility = 1.8
88
targetCompatibility = 1.8
99

10-
version = '2.7.0'
10+
version = '2.7.1'
1111

1212
repositories {
1313
mavenLocal()
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.raysmond.blog.admin.controllers;
2+
3+
import com.raysmond.blog.forms.SeoRobotAgentForm;
4+
import com.raysmond.blog.models.SeoRobotAgent;
5+
import com.raysmond.blog.repositories.SeoRobotAgentRepository;
6+
import com.raysmond.blog.utils.DTOUtil;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.stereotype.Controller;
9+
import org.springframework.ui.Model;
10+
import org.springframework.util.Assert;
11+
import org.springframework.validation.Errors;
12+
import org.springframework.web.bind.annotation.GetMapping;
13+
import org.springframework.web.bind.annotation.PathVariable;
14+
import org.springframework.web.bind.annotation.PostMapping;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
17+
import javax.validation.Valid;
18+
19+
@Controller
20+
@RequestMapping(value = "/admin/robotsAgents")
21+
public class SeoRobotAgentController {
22+
23+
@Autowired
24+
private SeoRobotAgentRepository seoRobotAgentRepository;
25+
26+
@GetMapping()
27+
public String getSeoRobotsAgents(Model model) {
28+
model.addAttribute("records", this.seoRobotAgentRepository.findAll());
29+
model.addAttribute("form", new SeoRobotAgentForm());
30+
return "admin/robotsAgents/index";
31+
}
32+
33+
34+
@GetMapping(value = "/{recordId:[\\d]+}/edit")
35+
public String editSeoRobotAgent(@PathVariable Long recordId, Model model) {
36+
37+
SeoRobotAgent ua = this.seoRobotAgentRepository.findOne(recordId);
38+
39+
Assert.notNull(ua);
40+
41+
model.addAttribute("form", DTOUtil.map(ua, SeoRobotAgentForm.class));
42+
43+
return "admin/robotsAgents/edit";
44+
}
45+
46+
@PostMapping(value = "/{recordId:[\\d]+}/edit")
47+
public String saveSeoRobotAgent(@PathVariable Long recordId, @Valid SeoRobotAgentForm form, Errors errors) {
48+
SeoRobotAgent ua = null;
49+
if (recordId.equals(0L)) {
50+
ua = new SeoRobotAgent();
51+
} else {
52+
ua = this.seoRobotAgentRepository.findOne(recordId);
53+
}
54+
Assert.notNull(ua);
55+
56+
DTOUtil.mapTo(form, ua);
57+
58+
this.seoRobotAgentRepository.save(ua);
59+
60+
return "redirect:/admin/robotsAgents";
61+
}
62+
63+
64+
@PostMapping(value = "/{recordId:[\\d]+}/delete")
65+
public String deleteSeoRobotAgent(@PathVariable Long recordId) {
66+
this.seoRobotAgentRepository.delete(recordId);
67+
return "redirect:/admin/robotsAgents";
68+
}
69+
70+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.raysmond.blog.forms;
2+
3+
import lombok.Data;
4+
5+
import javax.validation.constraints.NotNull;
6+
7+
@Data
8+
public class SeoRobotAgentForm {
9+
10+
@NotNull
11+
private Long id = 0L;
12+
13+
@NotNull
14+
private String userAgent = "";
15+
16+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.raysmond.blog.models;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import javax.persistence.*;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
@Entity
11+
@Table(name = "seo_robots_agents")
12+
@Getter
13+
@Setter
14+
public class SeoRobotAgent extends BaseModel {
15+
16+
@Column(nullable = false)
17+
private String userAgent;
18+
19+
public SeoRobotAgent() {
20+
21+
}
22+
23+
public SeoRobotAgent(String userAgent) {
24+
this.userAgent = userAgent;
25+
}
26+
27+
}

src/main/java/com/raysmond/blog/models/Visit.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import lombok.Getter;
44
import lombok.Setter;
55

6-
import javax.persistence.Column;
7-
import javax.persistence.Entity;
8-
import javax.persistence.ManyToOne;
9-
import javax.persistence.Table;
6+
import javax.persistence.*;
7+
import java.util.HashSet;
8+
import java.util.Set;
109

1110
@Entity
1211
@Table(name = "visits")
@@ -27,4 +26,5 @@ public class Visit extends BaseModel {
2726

2827
@Column
2928
private String userAgent;
29+
3030
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.raysmond.blog.repositories;
2+
3+
import com.raysmond.blog.models.SeoRobotAgent;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface SeoRobotAgentRepository extends JpaRepository<SeoRobotAgent, Long> {
7+
8+
}

src/main/java/com/raysmond/blog/repositories/VisitRepository.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,29 @@
33
import com.raysmond.blog.models.Post;
44
import com.raysmond.blog.models.User;
55
import com.raysmond.blog.models.Visit;
6+
import com.raysmond.blog.models.SeoRobotAgent;
67
import org.springframework.data.jpa.repository.JpaRepository;
78
import org.springframework.data.jpa.repository.Query;
89
import org.springframework.data.repository.query.Param;
910

11+
import java.util.List;
12+
1013
public interface VisitRepository extends JpaRepository<Visit, Long> {
14+
1115
@Query( "SELECT COUNT(DISTINCT v.clientIp) " +
1216
"FROM Visit AS v " +
13-
"WHERE v.post = :post AND v.isAdmin = FALSE "
17+
//"LEFT JOIN v.robotsAgents AS ra " +
18+
//"ON v.userAgent LIKE concat('%', ra.userAgent, '%') "+
19+
"WHERE v.post = :post AND v.isAdmin = FALSE " //+
20+
//"AND ra.id IS NULL "
1421
)
1522
Long getUniquePostVisitsCount(@Param("post") Post post);
23+
24+
@Query( "SELECT v.clientIp, NULLIF(v.userAgent, '') " +
25+
"FROM Visit AS v " +
26+
"WHERE v.post = :post AND v.isAdmin = FALSE " +
27+
"GROUP BY v.clientIp, NULLIF(v.userAgent, '') "
28+
)
29+
List<Object> getVisitsByPostAndIsAdminIsFalse(@Param("post") Post post);
30+
1631
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.raysmond.blog.services;
2+
3+
import org.springframework.stereotype.Service;
4+
5+
@Service
6+
public class SeoRobotAgentService {
7+
8+
9+
10+
}

src/main/java/com/raysmond/blog/services/VisitService.java

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
11
package com.raysmond.blog.services;
22

33
import com.raysmond.blog.models.Post;
4+
import com.raysmond.blog.models.SeoRobotAgent;
45
import com.raysmond.blog.models.User;
56
import com.raysmond.blog.models.Visit;
7+
import com.raysmond.blog.repositories.SeoRobotAgentRepository;
68
import com.raysmond.blog.repositories.VisitRepository;
9+
import org.hibernate.Hibernate;
10+
import org.hibernate.SQLQuery;
11+
import org.hibernate.Session;
12+
import org.hibernate.SessionFactory;
713
import org.springframework.beans.factory.annotation.Autowired;
14+
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
15+
import org.springframework.data.jpa.provider.HibernateUtils;
816
import org.springframework.stereotype.Service;
917

18+
import javax.persistence.EntityManager;
19+
import java.math.BigInteger;
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
import java.util.regex.Matcher;
23+
import java.util.regex.Pattern;
24+
1025
@Service
1126
public class VisitService {
1227

1328
@Autowired
1429
private VisitRepository visitRepository;
1530

31+
@Autowired
32+
private SeoRobotAgentRepository seoRobotAgentRepository;
33+
1634
@Autowired
1735
private UserService userService;
1836

37+
@Autowired
38+
private EntityManager entityManager;
39+
1940
public void saveVisit(Post post, String clientIp, String userAgent) {
2041
// if (this.userService.currentUser().isAdmin())
2142
// return;
@@ -32,7 +53,51 @@ public void saveVisit(Post post, String clientIp, String userAgent) {
3253
}
3354

3455
public Long getUniqueVisitsCount(Post post) {
35-
return this.visitRepository.getUniquePostVisitsCount(post);
56+
57+
Session session = (Session) this.entityManager.getDelegate();
58+
SQLQuery query = session.createSQLQuery(
59+
"SELECT COUNT(DISTINCT v.clientIp) " +
60+
"FROM visits AS v " +
61+
"LEFT JOIN seo_robots_agents AS ra " +
62+
"ON v.userAgent LIKE concat('%', ra.userAgent, '%') " +
63+
"WHERE v.post_id = :post_id AND v.isAdmin = FALSE " +
64+
"AND ra.id IS NULL ");
65+
query.setLong("post_id", post.getId());
66+
List<Object> result = query.list();
67+
if (result.size() > 0L) {
68+
return ((BigInteger)result.get(0)).longValue();
69+
}
70+
71+
return 0L;
72+
73+
}
74+
75+
public Long getUniqueVisitsCount_old(Post post) {
76+
//return this.visitRepository.getUniquePostVisitsCount(post);
77+
78+
// exclude queries from robots if matches by UserAgent
79+
List<SeoRobotAgent> robotsAgents = this.seoRobotAgentRepository.findAll();
80+
81+
final Long[] count = {0L};
82+
83+
this.visitRepository.getVisitsByPostAndIsAdminIsFalse(post).forEach(vr -> {
84+
85+
Object[] v = (Object[]) vr;
86+
87+
if (robotsAgents.size() == 0 || v[1] == null) {
88+
count[0]++;
89+
} else {
90+
robotsAgents.forEach(ra -> {
91+
Pattern p = Pattern.compile(".*("+ra.getUserAgent()+").*", Pattern.CASE_INSENSITIVE);
92+
Matcher m = p.matcher((String) v[1]);
93+
if (!m.matches()) {
94+
count[0]++;
95+
}
96+
});
97+
}
98+
});
99+
100+
return count[0];
36101
}
37102

38103
}
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

2-
form(method='POST', action='/admin/files/upload', enctype="multipart/form-data")
2+
form.post-form(method='POST', action='/admin/files/upload', enctype="multipart/form-data")
33
input(type="hidden", name='_csrf', value='#{_csrf.token}')
4-
input(type='file', name="file")
5-
br
6-
input(type='submit', value='Upload')
4+
.item-row
5+
input.form-control(type='file', name="file")
6+
.item-row
7+
input.btn.btn-primary(type='submit', value='Upload')

0 commit comments

Comments
 (0)