JPA一对多循环引用的解决&&JackSon无限递归问题
说是解决,其实不是很完美的解决的,写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的,能否知道一二。
下面说说出现问题:
问题是这样的,当我查询一个一对多的实体的时候,工具直接就爆了,差不多我就猜到是哪里死循环了,最后等了好久,查看原因,果然是堆溢出,再然后是jsckson的错误。那么必然是序列化的问题了。
这是jackson的错误:

- at java.security.AccessController.doPrivileged(Native Method)
- at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
- at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
- at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1617)
- at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
- at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:691)
- at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
- at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:656)
- at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)
- at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)

这是循环引用的错误:

- 严重: Servlet.service() for servlet [springDispatcherServlet] in context with path [/Shop] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError) (through reference chain: com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]-
- j。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。还有很多的相同的错误

下面是两个实体:
User.java:

- package com.web.module.index.model.entity;
- import java.io.Serializable;
- import java.util.HashSet;
- import java.util.Set;
- import javax.persistence.Entity;
- import javax.persistence.FetchType;
- import javax.persistence.Id;
- import javax.persistence.OneToMany;
- import javax.xml.bind.annotation.XmlAccessType;
- import javax.xml.bind.annotation.XmlAccessorType;
- import javax.xml.bind.annotation.XmlElement;
- import javax.xml.bind.annotation.XmlRootElement;
- import org.hibernate.validator.constraints.NotEmpty;
- import com.fasterxml.jackson.annotation.JsonIgnore;
- @XmlAccessorType(XmlAccessType.FIELD)
- @XmlRootElement(name="user")
- @Entity
- public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@XmlElement
@Id
private String id;
/**
* validate适用于springmvc
*/
@XmlElement
//@NotEmpty
private String name;
@JsonIgnore
@OneToMany(mappedBy="user",targetEntity=Account.class,fetch=FetchType.EAGER)
private Set</span><span style="color: #0000ff;"><</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">></span> accounts=new HashSet<span style="color: #0000ff;"><</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">></span><span style="color: #000000;">();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Set</span><span style="color: #0000ff;"><</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">></span><span style="color: #000000;"> getAccounts() {
return accounts;
}
public void setAccounts(Set</span><span style="color: #0000ff;"><</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">></span><span style="color: #000000;"> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", accounts=" + accounts
+ "]";
}
}

Account.java:

- package com.web.module.index.model.entity;
- import java.io.Serializable;
- import javax.persistence.CascadeType;
- import javax.persistence.Entity;
- import javax.persistence.FetchType;
- import javax.persistence.Id;
- import javax.persistence.JoinColumn;
- import javax.persistence.ManyToOne;
- import com.fasterxml.jackson.annotation.JsonIgnore;
- @Entity
- public class Account implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
private String id;
private String code;
private String password;
@JsonIgnore
@JoinColumn(name="user_id")
@ManyToOne(targetEntity=User.class,fetch=FetchType.EAGER)
private User user;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account [id=" + id + ", code=" + code + ", password="
+ password + ", user=" + user + "]";
}
}

后来去网上看了一下,这个问题很多人遇到。解决方案也有很多.
1.在关联的实体上面设置@JsonIgnore,这个注解的意思是表示在序列化的时候,忽略这个属性.但是我现在的逻辑是在页面中必须使用到这个关联实体中的属性,所以就不能这么做了,不然在页面中是取不出这个数据的。
- Uncaught TypeError: Cannot read property 'name' of undefined(1,2都会出现)
2.采用单向多对一的形式,这样就不会出现循环的问题,这个确实是个方案,但是如果在一的那边需要使用到多的这边的话,就不好搞了。所以感觉还是不是很满意。
3.后来想了想,既然是这样,要不我在一的那边使用@JsonIgnore吧。目前在页面中没使用。其实这个是第二个是差不多的,有点不同的是除了页面展示的时候不能够显示多的那面的数据,在其他的业务中还是能够使用的。这也是我在前面说不是很满意的解决办法。
4.第四种解决就是前面的3差不多,当我们使用多的一边的时候,可以正确的显示,但是在我们使用一的那一端的时候,我们可以使用List自己拼装,有点像下面的代码:

- @RequestMapping(value="result/{id}",method=RequestMethod.GET)
- public @ResponseBody List<?> result(@PathVariable("id") String id){
- System.out.println(id);
- List<Map<String,Object>> list=Lists.newArrayList();
- //Map<String,Object> map=new HashMap<String,Object>();
- Map<String,Object> map=null;
- Random r=new Random();
- DecimalFormat dfmt=new DecimalFormat("#,###.00");
- for(int i=0;i<4;i++){
- int price=r.nextInt(10)+1;
- int number=r.nextInt(100000)+10000;
- map=new HashMap<String,Object>();
- map.put("tradegoods", "煤"+i);
- map.put("units", "顿");
- map.put("consumer", "XX物流"+id);
- map.put("unitPrice", dfmt.format(price));
- map.put("number", dfmt.format(number));
- map.put("count", dfmt.format(price*number));
- list.add(map);
- }
- //设置日期格式
- return list;
- }

这样jackson序列化的时候,就不会出错了,而且使用起来就不用像A.B.name这样了,而且使用起来也更加的简单。我们在JS里面就可以这样使用:

- if(id!=""&&id){
- $.ajax({
- type: 'GET',
- url: $ctx + '/example/demo/result/'+id,
- dataType: 'json',
- success: function(data) {
- for(var i=;i<data.length;i++){
- data[i].num=i+;
- }
- //alert(JSON.stringify(data));
- viewModel.result(data);
- $(".notice-hide").show();
- $(".notice-show").hide();
- },
- error: function(req, textStatus, errorThrown){
- }
- });

html:

- <tbody data-bind="foreach: result">
- <tr>
- <td data-bind="text:num"></td>
- <td data-bind="text:tradegoods"></td>
- <td data-bind="text:units"></td>
- <td data-bind="text:consumer"></td>
- <td data-bind="text:unitPrice" class="format_"></td>
- <td data-bind="text:number" class="format_"></td>
- <td data-bind="text:count" class="format_"></td>
- </tr>
- </tbody>

这样就完美的解决了这个问题。
5添加Filter的方式进行动态的过滤属性 ,上面的解决方法还是或多或少的影响到我们正常的使用类,下面说的方法是不会影响放到原有的类的。
jsckson的ObjectMapper有一个

- public final void addMixInAnnotations(Class<?> target, Class<?> mixinSource)
- {
- _mixInAnnotations.put(new ClassKey(target), mixinSource);
- }
</span><span style="color: #0000ff;">public</span> final Class<?> findMixInClassFor(Class<?><span style="color: #000000;"> cls) {
</span><span style="color: #0000ff;">return</span> (_mixInAnnotations == <span style="color: #0000ff;">null</span>) ? <span style="color: #0000ff;">null</span> : _mixInAnnotations.<span style="color: #0000ff;">get</span>(<span style="color: #0000ff;">new</span><span style="color: #000000;"> ClassKey(cls));
}
</span><span style="color: #0000ff;">public</span> final <span style="color: #0000ff;">int</span><span style="color: #000000;"> mixInCount() {
</span><span style="color: #0000ff;">return</span> (_mixInAnnotations == <span style="color: #0000ff;">null</span>) ? <span style="color: #800080;">0</span><span style="color: #000000;"> : _mixInAnnotations.size();
}</span></pre>
这样的方法,这个方法的使用就要结合JsonIgnoreProperties注解一起来进行使用。我们需要定义一个接口,这个接口的作用是用来专门的过滤属性的。
还是针对上面的例子,我们要解决问题的话 ,我们需要在定义一个接口:

- package com.hotusm.jackson;
- import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
- @JsonIgnoreProperties(ignoreUnknown=true,value={"user"})
- public interface AccountFilter {
- }

这个接口非常简单,就是一个注解,注解其中的value就是表示的是我们需要将那些属性给忽略掉,增加了这么一个接口后,我们就可以使用上面提到的方法。
- objectMapper.addMixInAnnotations(Account.class, AccountFilter.class);
之后再使用这个objectmapper的时候,在account类上面的user就不会被忽略掉了,通过这种方式,我们不用修改原来类的任何地方。但是这种方式需要我们重新创建一个接口,所以下面一种就是解决这种每次都要创建的痛苦了。
6.利用自定义注解的方式来进行过滤,这种方式也是看到其他人使用,感觉非常好,也就做一个简单的总结。
大概的讲一下思路
1.还是使用addMixInAnnotations方法,但是不需要我们每次都创建一个接口而是采用全注解的形式来。也许会很奇怪,前面的方法命名
是传入两个class啊 ,我们不手动创建的话,那该怎样的去调用呢。这里我们使用字节码技术Javassist来动态的创建class。
2.大概的思路就是我们自定义方法级别注解,注解上面可以指定某些类上的哪些属性需要忽略。然后对这些方法进行增强,增强逻辑中获取到这些注解中的类以及这个类上面忽略的
下面是上面理论的一个简单的实践:
第一步:自定义注解:

- package com.hotusm.jackson.annotation;
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Inherited;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Target(ElementType.METHOD)
- @Documented
- @Retention(RetentionPolicy.RUNTIME)
- @Inherited
- public @interface IgnoreProperty {
- /
- * 指定类
- */
- Class<?> pojo();
</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
*指定上面的类那些属性需要过滤的
</span><span style="color: #008000;">*/</span><span style="color: #000000;">
String[] value();
}

上面这个注解就是我们后面要使用到的动态的在方法上面直接指定类需要忽略的属性。
第二步:对ObjectMapper进行装饰(写的例子,不是很优雅)

- package com.hotusm.jackson.annotation;
- import java.lang.reflect.Method;
- import java.util.Collection;
- import java.util.HashSet;
- import javassist.CannotCompileException;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.bytecode.AnnotationsAttribute;
- import javassist.bytecode.ClassFile;
- import javassist.bytecode.ConstPool;
- import javassist.bytecode.annotation.Annotation;
- import javassist.bytecode.annotation.ArrayMemberValue;
- import javassist.bytecode.annotation.BooleanMemberValue;
- import javassist.bytecode.annotation.MemberValue;
- import javassist.bytecode.annotation.StringMemberValue;
- import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
- import com.fasterxml.jackson.databind.ObjectMapper;
- public class ObjectMapperBuilder {
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ObjectMapper build(Method method) throws CannotCompileException{
IgnoreProperty ignoreProperty </span>= method.getAnnotation(IgnoreProperty.<span style="color: #0000ff;">class</span><span style="color: #000000;">);
String[] value </span>=<span style="color: #000000;"> ignoreProperty.value();
Class</span><?> pojo =<span style="color: #000000;"> ignoreProperty.pojo();
checkParamter(method,value,pojo);
Class</span><?> clazz=<span style="color: #000000;">doBuild(value);
ObjectMapper objectMapper</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ObjectMapper();
objectMapper.addMixInAnnotations(pojo, clazz);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> objectMapper;
}
</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
* 根据传入的参数构造一个class
* @throws CannotCompileException
</span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">public</span> Class<?><span style="color: #000000;"> doBuild(String[] values) throws CannotCompileException{
ClassPool pool </span>=<span style="color: #000000;"> ClassPool.getDefault();
CtClass cc </span>= pool.makeInterface(<span style="color: #800000;">"</span><span style="color: #800000;">ProxyMixInAnnotation</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> System.currentTimeMillis());
ClassFile classFile </span>=<span style="color: #000000;"> cc.getClassFile();
ConstPool cp </span>=<span style="color: #000000;"> classFile.getConstPool();
AnnotationsAttribute attr </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> AnnotationsAttribute(cp,
AnnotationsAttribute.visibleTag);
Annotation jsonIgnorePropertiesAnnotation </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> Annotation(
JsonIgnoreProperties.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getName(), cp);
BooleanMemberValue ignoreUnknownMemberValue </span>= <span style="color: #0000ff;">new</span> BooleanMemberValue(<span style="color: #0000ff;">false</span><span style="color: #000000;">, cp);
</span><span style="color: #008000;">//
ArrayMemberValue arrayMemberValue = new ArrayMemberValue(cp);
Collection<MemberValue> memberValues = new HashSet<MemberValue>();
for(int i=;i<values.length;i++){
StringMemberValue memberValue = new StringMemberValue(cp);// 将name值设入注解内
memberValue.setValue(values[i]);
memberValues.add(memberValue);
}
arrayMemberValue.setValue(memberValues.toArray(new MemberValue[]{}));
jsonIgnorePropertiesAnnotation.addMemberValue("value", arrayMemberValue);
jsonIgnorePropertiesAnnotation.addMemberValue("ignoreUnknown", ignoreUnknownMemberValue);
attr.addAnnotation(jsonIgnorePropertiesAnnotation);
classFile.addAttribute(attr);
Class clazz = cc.toClass();
return clazz;
}
protected void checkParamter(Object... objs){
boolean isTrue=true;
if(objsnull||objs.length<=){
isTrue=false;
}
for(Object obj:objs){
if(objnull){
isTrue=false;
}
}
if(!isTrue){
throw new RuntimeException("参数出现错误");
}
}
}

上面这一步我们已经看到了熟悉的addMixInAnnotations。后面的参数就是我们使用javassist根据value数组创建的动态类,这个动态类增加了一个很重要的注解就是JsonIgnoreProperties(这个注解就是我们6中讲的过滤属性的),现在通过build方法返回的ObjectMapper已经满足了动态的过滤属性的。
下面是一个测试:

- @Test
- @IgnoreProperty(pojo=Article.class,value={"user"})
- public void testJacksonAnnotation(){
- User user=new User();
- user.setName("hotusm");
- Article a1=new Article();
- a1.setTitle("t1");
- a1.setUser(user);
- Article a2=new Article();
- a2.setTitle("t2");
- a2.setUser(user);
- Article a3=new Article();
- a3.setTitle("t3");
- a3.setUser(user);
- List<Article> as=new ArrayList<Article>();
- as.add(a1);
- as.add(a2);
- as.add(a3);
- user.setArticles(as);
- ObjectMapper objectMapper;
- try {
- objectMapper = new ObjectMapperBuilder().build(Main.class.getMethod("testJacksonAnnotation"));
- String str = objectMapper.writeValueAsString(user);
- System.out.println(str);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }

在打印出来的json数据我们就可以明显的看出来已经把Article中的user属性给过滤掉了。(注意,user和article是一对多的关系)
总结:因为上面写的一个例子只是为了显示出问题,并没有进行代码的优化,以及功能的完善,如果是要在生产过程中使用的话,我们完全可以这样做:1.注解可以在类或者是方法上面2.所有多出来的操作都应该是对客户端程序员来说是透明的,我们可以通过方法的增强以及对ObjectMapper进行装饰。3.将方法或者类上面的注解信息放入到缓存中去,而不用发每次都要提取一次
2019-06-20更新
(1)在平时使用SpringMVC的时候也会出现这个问题,主要是SpringMVC的“@RestController”和“@ResponseBody”注解的序列化都调用了Jackson,因此只要是双向关系都会出现无限递归。感觉这个框架就是Hinbernate换了名字,我个人立场是十分不喜欢这种框架的。虽然看起来简单,不用写SQL但是,梳理关系和SQL的优化成本太高,不好干预。
(2)最好的解决方案使用JackSon2中的循环引用的序列化问题----使用"@JsonIdentityInfo"注解。这个注解如果每个实体的"property"的值都是"id"的话就会有问题,因此还得加一个"scope"属性才能正常使用,比如"@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = ServicioDTO.class))"。但是关于循环引用(recursive reference)问题如果用该annotion来解决的话要去映射关系中没有集合,有集合的话得采用其他方式,见下一条。。
(3)如果上面依旧不起作用,那么我们可以用"@JsonIgnore"注解来替代。这个方案就是方面3的方案,也经过试验了是可以的。
(4)针对映射实体中的复杂集合类型,可以用"@JsonManagedReference"和"@JsonBackReference"注解,这个也经过了试验是可以的.其实原理也比较相似就是将"@JsonBackReference"注解的对象序列化的时候忽略掉。Jackson看来对于递归引用的序列化问题还是没有彻底解决。
原文地址:https://www.cnblogs.com/zr520/archive/2016/04/06/5357459.html
JPA一对多循环引用的解决&&JackSon无限递归问题的更多相关文章
- JPA一对多循环引用的解决
说是解决,其实不是很完美的解决的,写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的,能否知道一二. 下面说说出现问题: 问题是这样的,当我查询一个一对多的实体的时候,工具直接就爆了,差不多我就 ...
- C#项目间循环引用的解决办法,有图有真相
C#项目间循环引用的解决办法,有图有真相 程序间的互相调用接口,c#禁止互相引用,海宏软件,20160315 /// c#禁止互相引用,如果项目[订单]中有一个orderEdit单元,要在项目[进销存 ...
- 在mvc返回JSON时出错:序列化类型为“System.Data.Entity.DynamicProxies.Photos....这个会的对象时检测到循环引用 的解决办法
在MVC中返回JSON时出错,序列化类型为“System.Data.Entity.DynamicProxies.Photos....这个会的对象时检测到循环引用. public ActionResul ...
- Block的使用及循环引用的解决
Block是一个很好用的东西,这篇文章主要来介绍:1.什么是Block?2.Block的使用?3.Block的循环引用问题及解决. 1.什么是Block? 说这个问题之前,我先来说一下闭包(Closu ...
- EF中Json序列化对象时检测到循环引用的解决办法
MVC4 EF中将数据表外键引用的是自身,转换成Json时,总是提示错误:“序列化类型为....的对象时检测到循环引用.”: 解决办法: 把要序列化的对象转为匿名对象去掉导航属性,如下 :本来是var ...
- IOS block 循环引用的解决
在介绍block循环引用前我们先了解一下typeof. typeof是什么??? typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型. 它返回值是一个字符串,该字符串说明运算数的类 ...
- Jackson-deserialization fails on circular dependencies(JackSon无限递归问题)
Ok, so I'm trying to test some stuffs with jackson json converter. I'm trying to simulate a graph be ...
- 解决ASP.NET MVC返回的JsonResult 中 日期类型数据格式问题,和返回的属性名称转为“驼峰命名法”和循环引用问题
DateTime类型数据格式问题 问题 在使用ASP.NET MVC 在写项目的时候发现,返回给前端的JSON数据,日期类型是 Date(121454578784541) 的格式,需要前端来转换一下才 ...
- 【JSON 注解】JSON循环引用1-----Jackson常用注解介绍 eq:@JsonIgnore
循环引用:实体A与实体B有关系,A中有B作为字段,B中有A作为一个字段.查询A对象后,将A对象转化为JSON格式数据时,会因为序列化过程中导致A中有B字段,B字段中又有A,这样就引起了循环引用的问题! ...
随机推荐
- Leetcode3.Longest Substring Without Repeating Characters无重复字符的最长字串
给定一个字符串,找出不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc",其长度为 ...
- Centos7搭建Django出现的问题(Centos7+Django1.11.1+Nginx+uwsgi)
出现的问题: 1.pip未安装:http://www.cnblogs.com/fnng/p/3737964.html 2.安装uwsgi失败,因为未安装python-devel yum search ...
- git gc干了啥
前几天在写升级项目的时候发现./git/objects/pack/下的idx和pack文件是只读的,用java在windows下删除会抛异常,然后把只读属性改掉就好了. 于是就想弄清楚这两个文件的作用 ...
- HDU - 4788 Hard Disk Drive (成都邀请赛H 水题)
HDU - 4788 Hard Disk Drive Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I ...
- day39-Spring 04-CGLIB的动态代理
JDK动态代理是有接口我给你创建一个类和你这个实现类是一样的, CGLIB不对实现接口的类生成代理,一个普通类也可以生成代理.CGLIB用继承的方式帮你生成代理对象.你父类有的方法我也有了,我想增强也 ...
- day39 09-Spring的AOP:基于AspectJ的通知类型
AspectJ的六种通知的类型,最后一种不讲,只讲前五种. 环绕通知是可以阻止目标方法执行的. <?xml version="1.0" encoding="UT ...
- 小爬爬6: 网易新闻scrapy+selenium的爬取
1.https://news.163.com/ 国内国际,军事航空,无人机都是动态加载的,先不管其他我们最后再搞中间件 2. 我们可以查看到"国内"等板块的位置 新建一个项目,创建 ...
- java 读取文内容(text,html)
1.将前端上传的html文件全部读取出来,并用string字符串返回出去解析的内容 public static String openFile(MultipartFile file) { try { ...
- 去除selet标签默认样式
select { /*Chrome和Firefox里面的边框是不一样的,所以复写了一下*/ border: solid 1px #000; /*很关键:将默认的select选择框样式清除*/ appe ...
- sql —— group by
说明: 从字面意义上理解就是根据“By”指定的规则对数据进行分组,所谓的分组就是将一个“数据集”划分成若干个“小区域”,然后针对若干个“小区域”进行数据处理. 原表: 执行分组查询: select G ...