用HibernateTemplate持久CGLIB代理实体 [英] Persisting CGLIB proxy entity with HibernateTemplate

查看:177
本文介绍了用HibernateTemplate持久CGLIB代理实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几乎到处都是搜索,但似乎没有人遇到过这个问题。
我有Spring MVC应用程序。
UserImpl实体在Context配置文件中被声明为request scoped bean,并由UsersController引用。 UsersController引用的UserImpl对象实际上是一个CGLib代理(这里是为什么?)。现在,当我第一次尝试用HibernateTemplate持久保存这样的代理对象时,我得到了这个错误:


org.hibernate.MappingException:未知实体:
main.mvc.model.hibernate.UserImpl $$ EnhancerByCGLIB $$ 9ac49631


经过一番搜索后,我发现: p>


org.springframework.orm.hibernate3.support.ScopedBeanInterceptor

哪种解决了这个问题。现在我没有得到MappingException并且实体被持久化了,但是......数据库记录中的每个字段都是空的。问题是什么?



注意:
当我硬编码UserImpl实例并使用UserServiceImpl持久化时,一切正常。



部分上下文配置:

 < bean id =userServiceclass =main.mvc.model .hibernate.UserServiceImpl/> 
< bean id =userValidatorclass =main.validators.UserValidator/>
< bean id =userWrapperValidatorclass =main.validators.UserWrapperValidator/>
< bean id =userclass =main.mvc.model.hibernate.UserImplscope =request>
< aop:scoped-proxy />
< / bean>
< bean id =sessionFactoryclass =org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean>
< property name =dataSourceref =dataSource/>
< property name =packagesToScanvalue =main.mvc.model.hibernate/>
< property name =entityInterceptor>
< bean class =org.springframework.orm.hibernate3.support.ScopedBeanInterceptor/>
< / property>
< property name =hibernateProperties>
<道具>
< prop key =hibernate.dialect> org.hibernate.dialect.HSQLDialect< / prop>
< prop key =hibernate.show_sql> true< / prop>
< prop key =hibernate.hbm2ddl.auto> update< / prop>
< /道具>
< / property>
< / bean>

UsersController:

  package main.mvc.controllers; 

import java.util.List;

import javax.inject.Inject;
import javax.validation.Valid;

import main.helpers.UserWrapper;
import main.mvc.model.User;
import main.mvc.model.UserService;
import main.mvc.model.hibernate.UserImpl;
import main.validators.UserValidator;
import main.validators.UserWrapperValidator;

导入org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;


@Controller
@RequestMapping(/ users)
public class UsersController {

private用户用户; //应该是请求范围的
private UserService userService;
private UserValidator userValidator;
private UserWrapperValidator userWrapperValidator;

@SuppressWarnings(unused)
private Logger logger = Logger.getLogger(getClass());

@Inject
public UsersController(User user,UserService userService,UserValidator userValidator,UserWrapperValidator userWrapperValidator){
this.user = user;
this.userService = userService;
this.userValidator = userValidator;
this.userWrapperValidator = userWrapperValidator;


@InitBinder(user)
protected void setUserValidator(WebDataBinder binder){
binder.setValidator(userValidator);


@InitBinder(userWrapper)
protected void setUserWrapperValidator(WebDataBinder binder){
binder.setValidator(userWrapperValidator);
}

@ModelAttribute
public UserWrapper wrapUser(){
return new UserWrapper(user);
}

// ================================== REQUEST HANDLERS ==========================================

@RequestMapping(value = {/ new},method = RequestMethod.GET)
public String showCreationForm(@ModelAttribute UserWrapper userWrapper){
returnuser_registration_form;

$ b @RequestMapping(method = RequestMethod.POST)
public String createUser(@Valid @ModelAttribute UserWrapper userWrapper,BindingResult bindingResult,RedirectAttributes redirectAttributes){
if( bindingResult.hasErrors()){
返回user_registration_form;
}
userService.save(userWrapper.getUser());
redirectAttributes.addFlashAttribute(message_title,Jakiśtext);
redirectAttributes.addFlashAttribute(message_text,Jakiśtext);
redirectAttributes.addFlashAttribute(redirect_url,/ users);
返回重定向:信息;
}
...
}

UserServiceImpl:

  public class UserServiceImpl extends HibernateDaoSupport implements UserService {

private PasswordEncoder passwordEncoder;
私人SaltSource saltSource;

@Inject
public UserServiceImpl(SessionFactory sessionFactory,PasswordEncoder passwordEncoder,SaltSource saltSource){
super();
setSessionFactory(sessionFactory);
setPasswordEncoder(passwordEncoder);
setSaltSource(saltSource);
}

public void save(用户用户){
创建时间=新日期();
user.setCreationDate(creationTime);
user.setLastModified(creationTime);

列表< Role> roles = new LinkedList<>();
roles.add(Role.ROLE_USER);
user.setRoles(roles);

Logger.getLogger(getClass())。info(user);
getHibernateTemplate()。save(user);
}
...
}

更新

好​​的,我添加了一些AOP魔术添加输出在ScoppedBeanInterceptor中处理实体对象时会发生什么。它完好无损。虽然Hibernate的BasicBinder将空值绑定到SQL语句。任何帮助?



log:

  11:27:51,866 DEBUG org.hibernate.SQL:111  - 选择userimpl0_.id作为id1_,userimpl0_.creationDate作为creation2_1_,userimpl0_.lastModified作为lastModi3_1_,userimpl0_.city作为city1_,userimpl0_.country作为country1_,userimpl0_.latitude作为纬度1_,userimpl0_.longitude作为longitude1_ ,使用shrimpl0_.postalCode作为postalCode1_,userimpl0_.street作为street1_,userimpl0_.birthDate作为birthDate1_,userimpl0_.firstName作为firstName1_,userimpl0_.secondName作为secondName1_,userimpl0_.sex作为sex1_,userimpl0_.surName作为surName1_,userimpl0_.alias作为alias1_,userimpl0_ .enabled as enabled1_,userimpl0_.loginEmail as loginEmail1_,userimpl0_.password as password1_,userimpl0_.preferences_id as prefere19_1_ from TBL_USER userimpl0_ where userimpl0_.loginEmail =? 
11:27:51,878 TRACE org.hibernate.type.descriptor.sql.BasicBinder:81 - 绑定参数[1]为[VARCHAR] - blady_the_best@o2.pl
11:27:52,009 INFO hsqldb .db.HSQLDB39E3504C79.ENGINE:? - 数据库关闭
11:27:52,225 DEBUG org.hibernate.SQL:111 - 选择userimpl0_.id作为id1_,userimpl0_.creationDate作为creation2_1_,userimpl0_.lastModified作为lastModi3_1_,userimpl0_.city作为city1_,userimpl0_.country作为country1_,userimpl0_.latitude as latitude1_,userimpl0_.longitude as longitude1_,userimpl0_.postalCode as postalCode1_,userimpl0_.street as street1_,userimpl0_.birthDate as birthDate1_,userimpl0_.firstName as firstName1_,userimpl0_.secondName as secondName1_,userimpl0_.secondName as second1_,userimpl0_.second as sex1_, userimpl0_.surName as surName1_,userimpl0_.alias as alias1_,userimpl0_.enabled as enabled1_,userimpl0_.loginEmail as loginEmail1_,userimpl0_.password as password1_,userimpl0_.preferences_id as prefere19_1_ from TBL_USER userimpl0_ where userimpl0_.alias =?
11:27:52,230 TRACE org.hibernate.type.descriptor.sql.BasicBinder:81 - 绑定参数[1]为[VARCHAR] - Bladositto
11:27:52,346 INFO hsqldb.db.HSQLDB39E3504C79 。发动机:? - 数据库关闭
11:27:52,470 INFO model.hibernate.UserServiceImpl:50 - User [id:null loginEmail:blady_the_best@o2.pl alias:Bladositto password:asdasd] class type:class model.hibernate.UserImpl $ $ EnhancerByCGLIB $$ 536b42dd
11:27:52,481 INFO helpers.EntityAuditor:13 - User [id:null loginEmail:blady_the_best@o2.pl alias:Bladositto password:asdasd]
11:27:52,483 INFO helpers.EntityAuditor:13 - 用户[id:null loginEmail:blady_the_best@o2.pl别名:Bladositto密码:asdasd]
11:27:52,581 DEBUG org.hibernate.SQL:111 - insert into TBL_USER(id,creationDate ,lastModified,城市,国家,纬度,经度,邮政编码,街道,birthDate,名字,secondName,性别,surName,别名,启用,loginEmail,密码,preferences_id)值(默认,?,?,?,?,?, ,?,?,?,?,?,?,?,?,?,?,?,?)
11:27:52,587 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding参数[1]为[TIMESTAMP] - < null>
11:27:52,589 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - 绑定参数[2]为[TIMESTAMP] - < null>
11:27:52,590 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [3] as [VARCHAR] - < null>
11:27:52,604 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [4] as [VARCHAR] - < null>
11:27:52,606 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [5] as [DOUBLE] - < null>
11:27:52,609 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [6] as [DOUBLE] - < null>
11:27:52,610 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [7] as [VARCHAR] - < null>
11:27:52,611 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [8] as [VARCHAR] - < null>
11:27:52,612 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - 绑定参数[9]与[DATE] - < null>
11:27:52,614 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - 绑定参数[10]为[VARCHAR] - < null>
11:27:52,615 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - 绑定参数[11]为[VARCHAR] - < null>
11:27:52,616 DEBUG org.hibernate.type.EnumType:136 - 将null绑定到参数:12
11:27:52,618 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - 绑定参数[13]作为[VARCHAR] - < null>
11:27:52,619 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [14] as [VARCHAR] - < null>
11:27:52,621 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [15] as [BIT] - < null>
11:27:52,621 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [16] as [VARCHAR] - < null>
11:27:52,623 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [17] as [VARCHAR] - < null>
11:27:52,625 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - 绑定参数[18]为[BIGINT] - < null>
11:27:52,767信息hsqldb.db.HSQLDB39E3504C79.ENGINE:? - 数据库已关闭


解决方案

默认情况下,Hibernate只是查看你传入的对象的类.Hibernate不知道这个Spring增强类。在Hibernate中,你需要注册一个 org.hibernate.EntityNameResolver ,这个合约允许自定义实体名称解析。 Really Spring应该可以注册它,但这只是一个小细节;)

或者你可以调用save()等形式。人。接受实体名称。例如,而不是:

  getHibernateTemplate()。save(user); 

用这个代替:

  getHibernateTemplate()。save(User.class.getName(),user); (假设Spring的HibernateTemplate实际上公开了这些方法,这实际上是一个很大的假设,根据我的经验和他们的经验模板类)。 

I've searched almost everywhere but no one seems to had this problem. I have Spring MVC application. There is UserImpl entity which is declared as request scoped bean in context configuration file and referenced by UsersController. The UserImpl object referenced by UsersController is actually a CGLib proxy (here is why?). Now when i first tried to persist such proxy object with HibernateTemplate I got this error:

org.hibernate.MappingException: Unknown entity: main.mvc.model.hibernate.UserImpl$$EnhancerByCGLIB$$9ac49631

After some search I found something like:

org.springframework.orm.hibernate3.support.ScopedBeanInterceptor

which kinda solved the problem. Now I don't get MappingException and entity is persisted but... every field in database record is null. What's the problem?

Note: When I hard code UserImpl instance and persist it with UserServiceImpl everything is OK.

Part of context config:

<bean id="userService" class="main.mvc.model.hibernate.UserServiceImpl"/>
<bean id="userValidator" class="main.validators.UserValidator"/>
<bean id="userWrapperValidator" class="main.validators.UserWrapperValidator"/>
<bean id="user" class="main.mvc.model.hibernate.UserImpl" scope="request">
    <aop:scoped-proxy/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="main.mvc.model.hibernate"/>
    <property name="entityInterceptor">
<bean class="org.springframework.orm.hibernate3.support.ScopedBeanInterceptor"/>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>

UsersController:

package main.mvc.controllers;

import java.util.List;

import javax.inject.Inject;
import javax.validation.Valid;

import main.helpers.UserWrapper;
import main.mvc.model.User;
import main.mvc.model.UserService;
import main.mvc.model.hibernate.UserImpl;
import main.validators.UserValidator;
import main.validators.UserWrapperValidator;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;


@Controller
@RequestMapping("/users")
public class UsersController {

    private User user; // should be request-scoped
    private UserService userService;
    private UserValidator userValidator;
    private UserWrapperValidator userWrapperValidator;

    @SuppressWarnings("unused")
    private Logger logger = Logger.getLogger(getClass());

    @Inject
    public UsersController(User user, UserService userService, UserValidator userValidator, UserWrapperValidator userWrapperValidator){
        this.user = user;
        this.userService = userService;
        this.userValidator = userValidator;
        this.userWrapperValidator = userWrapperValidator;
    }

    @InitBinder("user")
    protected void setUserValidator(WebDataBinder binder){
        binder.setValidator(userValidator);
    }

    @InitBinder("userWrapper")
    protected void setUserWrapperValidator(WebDataBinder binder){
        binder.setValidator(userWrapperValidator);
    }

    @ModelAttribute
    public UserWrapper wrapUser(){
        return new UserWrapper(user);
    }

    //==================================REQUEST HANDLERS==========================================

    @RequestMapping(value={"/new"}, method=RequestMethod.GET)
    public String showCreationForm(@ModelAttribute UserWrapper userWrapper){
        return "user_registration_form";
    }

    @RequestMapping(method=RequestMethod.POST)
    public String createUser(@Valid @ModelAttribute UserWrapper userWrapper, BindingResult bindingResult, RedirectAttributes redirectAttributes){
        if(bindingResult.hasErrors()){
            return "user_registration_form";
        }
        userService.save(userWrapper.getUser());
        redirectAttributes.addFlashAttribute("message_title", "Jakiś text");
        redirectAttributes.addFlashAttribute("message_text", "Jakiś text");
        redirectAttributes.addFlashAttribute("redirect_url", "/users");
        return "redirect:information";
    }
...
}

UserServiceImpl:

public class UserServiceImpl extends HibernateDaoSupport implements UserService {

    private PasswordEncoder passwordEncoder;
    private SaltSource saltSource;

    @Inject
    public UserServiceImpl(SessionFactory sessionFactory, PasswordEncoder passwordEncoder, SaltSource saltSource) {
        super();
        setSessionFactory(sessionFactory);
        setPasswordEncoder(passwordEncoder);
        setSaltSource(saltSource);
    }

    public void save(User user) {
        Date creationTime = new Date();
        user.setCreationDate(creationTime);
        user.setLastModified(creationTime);

        List<Role> roles = new LinkedList<>();
        roles.add(Role.ROLE_USER);
        user.setRoles(roles);

        Logger.getLogger(getClass()).info(user);
        getHibernateTemplate().save(user);
    }
...
}

Update
Ok so I've added some AOP magic add output what happens to the entity object while processed in ScoppedBeanInterceptor. It's intact. Although Hibernate's BasicBinder is binding null values to the SQL statement. Any help?

log:

11:27:51,866 DEBUG org.hibernate.SQL:111 - select userimpl0_.id as id1_, userimpl0_.creationDate as creation2_1_, userimpl0_.lastModified as lastModi3_1_, userimpl0_.city as city1_, userimpl0_.country as country1_, userimpl0_.latitude as latitude1_, userimpl0_.longitude as longitude1_, userimpl0_.postalCode as postalCode1_, userimpl0_.street as street1_, userimpl0_.birthDate as birthDate1_, userimpl0_.firstName as firstName1_, userimpl0_.secondName as secondName1_, userimpl0_.sex as sex1_, userimpl0_.surName as surName1_, userimpl0_.alias as alias1_, userimpl0_.enabled as enabled1_, userimpl0_.loginEmail as loginEmail1_, userimpl0_.password as password1_, userimpl0_.preferences_id as prefere19_1_ from TBL_USER userimpl0_ where userimpl0_.loginEmail=?
11:27:51,878 TRACE org.hibernate.type.descriptor.sql.BasicBinder:81 - binding parameter [1] as [VARCHAR] - blady_the_best@o2.pl
11:27:52,009  INFO hsqldb.db.HSQLDB39E3504C79.ENGINE:? - Database closed
11:27:52,225 DEBUG org.hibernate.SQL:111 - select userimpl0_.id as id1_, userimpl0_.creationDate as creation2_1_, userimpl0_.lastModified as lastModi3_1_, userimpl0_.city as city1_, userimpl0_.country as country1_, userimpl0_.latitude as latitude1_, userimpl0_.longitude as longitude1_, userimpl0_.postalCode as postalCode1_, userimpl0_.street as street1_, userimpl0_.birthDate as birthDate1_, userimpl0_.firstName as firstName1_, userimpl0_.secondName as secondName1_, userimpl0_.sex as sex1_, userimpl0_.surName as surName1_, userimpl0_.alias as alias1_, userimpl0_.enabled as enabled1_, userimpl0_.loginEmail as loginEmail1_, userimpl0_.password as password1_, userimpl0_.preferences_id as prefere19_1_ from TBL_USER userimpl0_ where userimpl0_.alias=?
11:27:52,230 TRACE org.hibernate.type.descriptor.sql.BasicBinder:81 - binding parameter [1] as [VARCHAR] - Bladositto
11:27:52,346  INFO hsqldb.db.HSQLDB39E3504C79.ENGINE:? - Database closed
11:27:52,470  INFO model.hibernate.UserServiceImpl:50 - User[id: null    loginEmail: blady_the_best@o2.pl    alias: Bladositto   password: asdasd]   class type:class model.hibernate.UserImpl$$EnhancerByCGLIB$$536b42dd
11:27:52,481  INFO helpers.EntityAuditor:13 - User[id: null  loginEmail: blady_the_best@o2.pl    alias: Bladositto   password: asdasd]
11:27:52,483  INFO helpers.EntityAuditor:13 - User[id: null  loginEmail: blady_the_best@o2.pl    alias: Bladositto   password: asdasd]
11:27:52,581 DEBUG org.hibernate.SQL:111 - insert into TBL_USER (id, creationDate, lastModified, city, country, latitude, longitude, postalCode, street, birthDate, firstName, secondName, sex, surName, alias, enabled, loginEmail, password, preferences_id) values (default, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
11:27:52,587 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [1] as [TIMESTAMP] - <null>
11:27:52,589 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [2] as [TIMESTAMP] - <null>
11:27:52,590 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [3] as [VARCHAR] - <null>
11:27:52,604 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [4] as [VARCHAR] - <null>
11:27:52,606 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [5] as [DOUBLE] - <null>
11:27:52,609 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [6] as [DOUBLE] - <null>
11:27:52,610 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [7] as [VARCHAR] - <null>
11:27:52,611 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [8] as [VARCHAR] - <null>
11:27:52,612 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [9] as [DATE] - <null>
11:27:52,614 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [10] as [VARCHAR] - <null>
11:27:52,615 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [11] as [VARCHAR] - <null>
11:27:52,616 DEBUG org.hibernate.type.EnumType:136 - Binding null to parameter: 12
11:27:52,618 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [13] as [VARCHAR] - <null>
11:27:52,619 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [14] as [VARCHAR] - <null>
11:27:52,621 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [15] as [BIT] - <null>
11:27:52,621 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [16] as [VARCHAR] - <null>
11:27:52,623 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [17] as [VARCHAR] - <null>
11:27:52,625 TRACE org.hibernate.type.descriptor.sql.BasicBinder:70 - binding parameter [18] as [BIGINT] - <null>
11:27:52,767  INFO hsqldb.db.HSQLDB39E3504C79.ENGINE:? - Database closed

解决方案

The "Unknown entity" bit is because by default Hibernate just looks at the class of the object you pass in. Hibernate has no idea about this Spring-enhanced class. In Hibernate terms you would need to register a org.hibernate.EntityNameResolver which is contract to allow custom entity name resolution. Really Spring should probably be registering it, but thats a minor detail ;)

Alternately you could call the form of save() et. al. that accept the entity name. For example, rather than:

getHibernateTemplate().save( user );

use this instead:

getHibernateTemplate().save( User.class.getName(), user );

(assuming Spring's HibernateTemplate actually exposes those methods, which is actually quite a big assumption given my experience with their template classes).

这篇关于用HibernateTemplate持久CGLIB代理实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆