说是解决,其实不是很完美的解决的,写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的,能否知道一二。

下面说说出现问题:

问题是这样的,当我查询一个一对多的实体的时候,工具直接就爆了,差不多我就猜到是哪里死循环了,最后等了好久,查看原因,果然是堆溢出,再然后是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;">&lt;</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">&gt;</span> accounts=new HashSet<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">&gt;</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;">&lt;</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"> getAccounts() {
return accounts;
} public void setAccounts(Set</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Account</span><span style="color: #0000ff;">&gt;</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&lt;?&gt; findMixInClassFor(Class&lt;?&gt;<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>&lt;?&gt; pojo =<span style="color: #000000;"> ignoreProperty.pojo();
checkParamter(method,value,pojo);
Class</span>&lt;?&gt; 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&lt;?&gt;<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无限递归问题的更多相关文章

  1. JPA一对多循环引用的解决

    说是解决,其实不是很完美的解决的,写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的,能否知道一二. 下面说说出现问题: 问题是这样的,当我查询一个一对多的实体的时候,工具直接就爆了,差不多我就 ...

  2. C#项目间循环引用的解决办法,有图有真相

    C#项目间循环引用的解决办法,有图有真相 程序间的互相调用接口,c#禁止互相引用,海宏软件,20160315 /// c#禁止互相引用,如果项目[订单]中有一个orderEdit单元,要在项目[进销存 ...

  3. 在mvc返回JSON时出错:序列化类型为“System.Data.Entity.DynamicProxies.Photos....这个会的对象时检测到循环引用 的解决办法

    在MVC中返回JSON时出错,序列化类型为“System.Data.Entity.DynamicProxies.Photos....这个会的对象时检测到循环引用. public ActionResul ...

  4. Block的使用及循环引用的解决

    Block是一个很好用的东西,这篇文章主要来介绍:1.什么是Block?2.Block的使用?3.Block的循环引用问题及解决. 1.什么是Block? 说这个问题之前,我先来说一下闭包(Closu ...

  5. EF中Json序列化对象时检测到循环引用的解决办法

    MVC4 EF中将数据表外键引用的是自身,转换成Json时,总是提示错误:“序列化类型为....的对象时检测到循环引用.”: 解决办法: 把要序列化的对象转为匿名对象去掉导航属性,如下 :本来是var ...

  6. IOS block 循环引用的解决

    在介绍block循环引用前我们先了解一下typeof. typeof是什么??? typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型. 它返回值是一个字符串,该字符串说明运算数的类 ...

  7. 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 ...

  8. 解决ASP.NET MVC返回的JsonResult 中 日期类型数据格式问题,和返回的属性名称转为“驼峰命名法”和循环引用问题

    DateTime类型数据格式问题 问题 在使用ASP.NET MVC 在写项目的时候发现,返回给前端的JSON数据,日期类型是 Date(121454578784541) 的格式,需要前端来转换一下才 ...

  9. 【JSON 注解】JSON循环引用1-----Jackson常用注解介绍 eq:@JsonIgnore

    循环引用:实体A与实体B有关系,A中有B作为字段,B中有A作为一个字段.查询A对象后,将A对象转化为JSON格式数据时,会因为序列化过程中导致A中有B字段,B字段中又有A,这样就引起了循环引用的问题! ...

随机推荐

  1. Vue源码探究-虚拟DOM的渲染

    Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...

  2. Android基础&进阶

    基础总结篇之一:Activity生命周期 基础总结篇之二:Activity的四种launchMode 基础总结篇之三:Activity的task相关 基础总结篇之四:Service完全解析 基础总结篇 ...

  3. Oracle企业管理框架

    oracle管理服务器 是一个基于java的web构件,该构件是dba用来监视和控制oracle企业框架内各个受管理目标的实际界面 oracle储存库 已收集到并与受管理目标有关的配置和监视信息被存储 ...

  4. 洛谷 P3950 部落冲突 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例1 输出样例1 输入样例2 输出样例2 输入样例3 输出样例3 说明 思路 AC代码 总结 题面 题目链接 P3 ...

  5. 【水滴石穿】react-native-book

    先推荐一个学习的地址:https://ke.qq.com/webcourse/index.html#cid=203313&term_id=100240778&taid=12778558 ...

  6. php中array_slice和array_splice函数解析方式方法

    array_slice array array_slice ( array $array , int $offset [, int $length = NULL [, bool $preserve_k ...

  7. DOM修改元素的方法总结

    今天我们要谈谈DOM元素的修改(包括修改内容,属性,样式).修改内容的方法----3种:elem.innerHTML:获取或设置元素开始标签到结束标签之间的原始HTML代码片段:elem.textCo ...

  8. Jeff Dean 光辉事迹

    这是Google 2007年的愚人节笑话,罗列了很多Jeff Dean的“光辉事迹”.大名鼎鼎的Jeff Dean想必不用我介绍了.……好吧,还是介绍一下,Jeff Dean是Google最早的一批员 ...

  9. sql —— in

    IN 操作符允许我们在 WHERE 子句中规定多个值. 原表: 执行查询:

  10. framework7日期插件使用

    1.引入框架文件 <link rel="stylesheet" href="framework7.ios.min.css"> <link re ...