admin管理员组

文章数量:1640010

  1. 前言
    第一次在csdn上发布blog,还是有点紧张的,代码写得太差会不会被吐槽,架构不好会不会被喷,总之最后还是抛弃了这些因素,源于一个学长吧,做什么事都有第一次呢,丑媳妇还是要见公婆的,把项目贴出来就是为了能学习一些更好的开发方法,取人之长,补己之短。在这些激烈的探讨过程中,大家一起学习,一起进步,好了,废话不多说了,直接进主题吧。
    2.概述
    现在大多数访问量比较大的网站都采用了QQ等第三方账号接入系统,QQ一键登录更可减少登录交互操作,大大降低网站注册门槛,给网站带来海量新用户。这里也就不再赘述,具体可以见[QQ接入概述](http://wiki.connect.qq/%E7%BD%91%E7%AB%99%E6%8E%A5%E5%85%A5%E6%A6%82%E8%BF%B0) ,前几天到网上搜了下,关于Java接入QQ登录的文章比较少,大部分都是官方给的API,也有一部分是PHP的,为了能够让一些初学spring的同学能够快速使用spring框架结合QQ官方给的接入API开发出自己的应用系统接入QQ登录的简单解决方案,所以开发了这个小项目,给大家分享。
    3.开发前环境准备
    1.Spring的基础开发环境,jdk+tomcat+myeclipse+spring,这些就不用说了吧,标配就可以了
    2.申请一个免费的域名,本人是使用花生壳来搭建内网服务的,具体申请地址可以参考:[花生壳搭建网站]。目的是能够QQ互联官网申请appid时通过腾讯的网址验证,也就是让其能访问我们的域名(http://service.oray/question/1669.html%20%E4%BD%BF%E7%94%A8%E8%8A%B1%E7%94%9F%E5%A3%B3%E6%90%AD%E5%BB%BA%E7%BD%91%E7%AB%99)
    3.开通新花生壳内网版服务,并在服务器电脑上下载新花生壳1.0客户端。
    4.[下载新花生壳1.0客户端]并配置好相关映射(http://hsk.oray/download/%20%E4%B8%8B%E8%BD%BD%E6%96%B0%E8%8A%B1%E7%94%9F%E5%A3%B31.0%E5%AE%A2%E6%88%B7%E7%AB%AF)




    5.为应用申请appid和appkey,申请地址QQ互联管理中心


    注意:1.验证地址时请将其提供的meta代码复制粘贴至你的服务器根目录下的首页,进入tomcat的webapps->ROOT,打开index.jsp,在之间将其提供的meta代码粘贴保存,然后重启tomcat,便可验证成功。

    2.回调地址暂时可填与主页相同的地址(在Controller层开发完成后可到QQ互联的管理中心修改)
  2. 验证成功后便可获得appid和appkey,根据此appid和appkey便可着手进行登录业务的代码层面的开发

    6.下载QQ官方给的Java SDK:[Java SDK下载](http://wiki.connect.qq/sdk%E4%B8%8B%E8%BD%BD%20Java%20SDK%E4%B8%8B%E8%BD%BD)
    下载后的文件结构目录如下:

    –sdk4j_demo:官方demo
    –sdk4j_doc:官方文档,描述类详情(可以好好看看)
    –qqconnectconfig.properties:配置qq登录详细信息的配置文件,配置如下

    –Sdk4J.jar 官方jar包,粘贴至工程WEB-INF的libs目录下,并加入到类路径中(必不可少的jar包)
    7在myeclipse中新建web工程,目录应该如下所示


    关于各类的说明
    虽然此次只是开发一个简单的QQ登录功能,但是我们还是 沿用一般spring的架构,采用经典的三层的结构设计,即持久层,业务层,控制层。这样可做到系统模块间相互分离,有利于系统的二次开发,大家在实际开发过程中必定能领悟这种设计的优点,同学们在初学过程中也要仔细体会这种架构的精髓。
    下面贴出具体的代码部分,仅供大家参考

com.wuning.constant包(武宁是我的县名,这个项目也是为县大学生共进社开发的)
ConstantQuantity ,提供一些常量的定义,方便引用,包括SQL语句和appid

package com.wuning.constant;

public class ConstantQuantity {
    /**
     * 根据用户Id查询用户匹配的记录数
     */
    public static final String QUERYUSERCOUNT_BY_USER_ID="SELECT COUNT(*) FROM test_user WHERE user_id=?";
    /**
     * 根据用户OpenId查询用户匹配的记录数
     */
    public static final String QUERYUSERCOUNT_BY_TPA_OPENID="SELECT COUNT(*) FROM test_user WHERE user_tpa_openid=?";
    /**
     * 根据用户Id查询用户信息的SQL语句
     */
    public static final String QUERYUSER_BY_USER_ID="SELECT * FROM test_user WHERE user_id=?";
    /**
     * 根据用户OpenId查询用户信心的SQL语句
     */
    public static final String QUERYUSER_BY_USER_TPA_OPENID="SELECT * FROM test_user WHERE user_tpa_openid=?";
    /**
     * 保存用户信息的语句
     */
    public static final String SAVEUSER="INSERT INTO test_user(user_tpa_openid,user_name,user_password,user_createtime,user_image_url)VALUES(?,?,?,?,?)";
    /**
     * 应用id
     */
    public static final String APPID="********";
    /**
     * 请求地址
     */
    public static final String URL="https://graph.qq/user/get_user_info";
}

com.wuning.enity包的User类
实体类,存储用户的相关信息,大家也可以根据自己的项目自行添加或删除一些属性

package com.wuning.enity;

import java.util.Date;

/**
 * Enity 用户(待完善)
 * @author zhouxuewen
 * {@link ...}
 *
 */
public class User {
    /**
     * 用户ID
     */
    private int user_id;
    /**
     * 第三方登录用户ID(例如QQ用户的openID),该ID需持久化到数据库中,方便用户下次登录
     */
    private String user_tpa_openid;
    /**
     * 用户名
     */
    private String user_name;
    /**
     * 用户密码
     */
    private String user_password;
    /**
     * 用户头像url
     */
    public String user_image_url;
    /**
     * 用户注册时间
     */
    private Date user_createTime;

    public int getUser_id() {
        return user_id;
    }
    public void setUser_id(int user_id) {
        this.user_id = user_id;
    }
    public String getUser_tpa_openid() {
        return user_tpa_openid;
    }
    public void setUser_tpa_openid(String user_tpa_openid) {
        this.user_tpa_openid = user_tpa_openid;
    }
    public String getUser_name() {
        return user_name;
    }
    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }
    public String getUser_password() {
        return user_password;
    }
    public void setUser_password(String user_password) {
        this.user_password = user_password;
    }
    public Date getUser_createTime() {
        return user_createTime;
    }
    public void setUser_createTime(Date user_createTime) {
        this.user_createTime = user_createTime;
    }
    public String getUser_image_url() {
        return user_image_url;
    }
    public void setUser_image_url(String user_image_url) {
        this.user_image_url = user_image_url;
    }



}

接口类IUserDao,提供用户相关操作的接口类

package com.wuning.dao;

import com.wuning.enity.User;

public interface IUserDao {
    /**
     * 根据用户ID查询用户是否存在,存在则返回1,不存在则返回0
     * @param user_id
     * @return int
     */
    public int getMatchCountByUserId(int user_id);
    /**
     * 根据第三方用户的OpenID查询用户是否存在,存在则返回1,不存在则返回0
     * @param user_tpa_openid
     * @return int 
     */
    public int getMatchCountByUserTpaId(String user_tpa_openid);
    /**
     * 根据userid查询用户
     * @param user_id
     * @return user
     */
    public User findUserByUserId(int user_id);
    /**
     * 根据user_tpa_openid查询用户
     * @param user_tpa_openid
     * @return user
     */
    public User findUserByTpaOpenId(String user_tpa_openid);
    /**
     * 注册新用户
     * @param user
     */
    public void saveNewsUser(User user);


}

IUserDao接口实现类UserDaoImp

package com.wuning.dao;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;

import com.wuning.constant.ConstantQuantity;
import com.wuning.enity.User;

/**
 * Dao 持久化用户信息数据到数据库中
 * @author 18720082476
 *
 */
@Repository
public class UserDaoImp implements IUserDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public User findUserByUserId(final int user_id){
        // TODO Auto-generated method stub
        final User user=new User();
        jdbcTemplate.query(ConstantQuantity.QUERYUSER_BY_USER_ID, new Object[] {user_id},
                new RowCallbackHandler() {
                    public void processRow(ResultSet rs) throws SQLException {
                        // 设置用户信息
                        user.setUser_id(user_id);
                        user.setUser_tpa_openid(rs.getString("user_tpa_openid"));
                        user.setUser_name(rs.getString("user_name"));
                        user.setUser_image_url(rs.getString("user_image_url"));
                        user.setUser_createTime(rs.getDate("user_createTime"));

                    }

                });
        return user;
    }

    @Override
    public User findUserByTpaOpenId(final String  user_tpa_openid) {
        // TODO Auto-generated method stub
        final User user=new User();
        jdbcTemplate.query(ConstantQuantity.QUERYUSER_BY_USER_TPA_OPENID, new Object[] {user_tpa_openid},
                new RowCallbackHandler() {
                    public void processRow(ResultSet rs) throws SQLException {
                        // 设置用户信息
                        user.setUser_id(rs.getInt("user_id"));
                        user.setUser_tpa_openid(user_tpa_openid);
                        user.setUser_name(rs.getString("user_name"));
                        user.setUser_image_url(rs.getString("user_image_url"));
                        user.setUser_createTime(rs.getDate("user_createTime"));
                    }

                });
        return user;
    }

    @Override
    public void saveNewsUser(User user) {
        // TODO Auto-generated method stub

        jdbcTemplate.update(ConstantQuantity.SAVEUSER, new Object[]{user.getUser_tpa_openid(),user.getUser_name(),user.getUser_password(),user.getUser_createTime(),user.getUser_image_url()});


    }

    @Override
    public int getMatchCountByUserId(int user_id) {
        // TODO Auto-generated method stub
        return jdbcTemplate.queryForInt(ConstantQuantity.QUERYUSERCOUNT_BY_USER_ID, new Object[]{user_id});
    }

    @Override
    public int getMatchCountByUserTpaId(String user_tpa_openid) {
        // TODO Auto-generated method stub
        return  jdbcTemplate.queryForInt(ConstantQuantity.QUERYUSERCOUNT_BY_TPA_OPENID, new Object[]{user_tpa_openid});
    }



}

用户业务的接口定义类IUserService

package com.wuning.service;

import javax.servlet.http.HttpServletRequest;

import com.qq.connect.QQConnectException;
import com.wuning.enity.User;

/**
 * 用户Service
 * @author 18720082476
 *
 */
public interface IUserService {
       /**
        * 验证第三方应用授权的用户是否已存在用户列表中
        * @param user_tpa_openid
        * @return
        */
       public int getMatchCountByUserTpaId(String user_tpa_openid);
       /**
        * 根据user_tpa_openid查询用户信息并返回User实例
        * @param user_tpa_openid
        * @return
        */
       public User findUserByTpaOpenId(String user_tpa_openid);
       /**
        * 注册用户
        * @param user
        */
       public void saveNewUser(User user);
       //QQ登录
        /**
         * 根据授权成功后返回的redirect_uri地址后带的Authorization Code和原始的state值解析Access Token
         * 进而获取opendID,构造用户信息并返回
         * @param request
         * @return
         */
       public User getUserByOAuthOfQQ(HttpServletRequest request)throws QQConnectException;
       //新浪微博登陆
       //未实现

}

用户登录业务的实现类UserLoginServiceImp

package com.wuning.service;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import com.qq.connect.QQConnectException;
import com.qq.connect.api.OpenID;
import com.qq.connect.api.qzone.UserInfo;
import com.qq.connect.javabeans.AccessToken;
import com.qq.connect.javabeans.qzone.UserInfoBean;
import com.qq.connect.oauth.Oauth;
import com.wuning.constant.ConstantQuantity;
import com.wuning.dao.UserDaoImp;
import com.wuning.enity.User;
import com.wuning.util.HttpUtil;
@Service
public class UserLoginServiceImp implements IUserService {
    @Autowired
    private UserDaoImp userDaoImp;
    @Override
    public int getMatchCountByUserTpaId(String user_tpa_openid) {
        // TODO Auto-generated method stub
        return userDaoImp.getMatchCountByUserTpaId(user_tpa_openid);
    }

    @Override
    public User findUserByTpaOpenId(String user_tpa_openid) {
        // TODO Auto-generated method stub
        return userDaoImp.findUserByTpaOpenId(user_tpa_openid);
    }

    @Override
    public void saveNewUser(User user) {
        // TODO Auto-generated method stub
       userDaoImp.saveNewsUser(user);
    }

    @Override
    public User getUserByOAuthOfQQ(HttpServletRequest request) throws QQConnectException {
        // TODO Auto-generated method stub
         final User user=new User();
         String accessToken=null,
                 openID=null;
         long tokenExpireIn = 0L;
         //--------------官方代码-----------------------------------------------
         //以下代码由腾讯官方Java SDK给出,详见:http://wiki.connect.qq/sdk下载,所用到的
         //类也均在腾讯官方给的Sdk4J.jar中给出
         //根据返回的request解析出AccessToken对象
         AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);

         if (accessTokenObj.getAccessToken().equals("")) {
             //我们的网站被CSRF攻击了或者用户取消了授权
             //做一些数据统计工作
                    System.out.print("没有获取到响应参数");
                } else {
                    //获取accessToken信息
                    accessToken = accessTokenObj.getAccessToken();

                    tokenExpireIn = accessTokenObj.getExpireIn();

                    // 利用获取到的accessToken 去获取当前用的openid -------- start
                    OpenID openIDObj =  new OpenID(accessToken);
                    //获取openid
                    openID = openIDObj.getUserOpenID();

                    System.out.println("欢迎你,代号为 " + openID + " 的用户!");

                    //根据accessToken和openID获取UserInfo对象

                    UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);

                    //获取bean
                    UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();
          //---------------------------官方代码结束----------------------------
          //用户信息获取完成,接下来根据我们应用的具体情况获取用户在QQ上的资料,构造自己的User
                    /*ret   返回码
                    msg 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。
                    nickname    用户在QQ空间的昵称。
                    figureurl   大小为30×30像素的QQ空间头像URL。
                    figureurl_1 大小为50×50像素的QQ空间头像URL。
                    figureurl_2 大小为100×100像素的QQ空间头像URL。
                    figureurl_qq_1  大小为40×40像素的QQ头像URL。
                    figureurl_qq_2  大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有。
                    gender  性别。 如果获取不到则默认返回"男"
                    is_yellow_vip   标识用户是否为黄钻用户(0:不是;1:是)。
                    vip 标识用户是否为黄钻用户(0:不是;1:是)
                    yellow_vip_level    黄钻等级
                    level   黄钻等级
                    is_yellow_year_vip  标识是否为年费黄钻用户(0:不是; 1:是)    */

                    //设置用户名为QQ用户在QQ空间的昵称
                    user.setUser_name(userInfoBean.getNickname());
                    //设置用户的openid为获取的openid
                    user.setUser_tpa_openid(openID);
                    //设置用户的头像地址,该头像来自QQ空间的头像
                    //user.setUser_image_url(userInfoBean.getAvatar().getAvatarURL50());
                    System.out.println("第一个头像地址:"+userInfoBean.getAvatar().getAvatarURL50());
                    //设置用户的头像地址,该头像来自QQ头像
                    String user_img_url=HttpUtil.sendGet(ConstantQuantity.URL, ConstantQuantity.APPID, accessToken, openID);
                    user.setUser_image_url(user_img_url);
                    System.out.println("第二个头像地址:"+user_img_url);
                    //设置用户密码为空
                    user.setUser_password("");
                    //设置创建时间
                    user.setUser_createTime(new Date());


              }
            return user;
    }

}

UserLoginService的核心方法即为getUserByOAuthOfQQ,通过该方法我们获取到用户QQ的相关资料信息,并返回User给控制层调用,需要注意的是,在设置用户头像url的时候有两种选择,一是可以设置为用户的QQ空间头像,直接调用userInfoBean.getAvatar().getAvatarURL50()返回头像地址即可,二是可以设置为用户的QQ头像,由于在官方的给的API中并没有给出获取QQ头像的调用方法,我这里采用的是根据腾讯官方提供的API,利用http请求获取用户的信息,调用该接口返回的字符串数据中包含QQ头像的url,于是分析该字符串便可以得到QQ头像的url,设置到用户的image属性中。这里大家可以根据自己应用来做不同的选择.以下是Http实现类,参考了java实现http GET/POST请求

package com.wuning.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.URL;
import java.URLConnection;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;

public class HttpUtil {
    /**
     * 向指定URL发送GET方法的请求
     * 
     * @param url
     *            发送请求的URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String appid,String access_token,String opendid) {
        String result = "";
        String  param="oauth_consumer_key="+appid+"&access_token="+access_token+"&openid="+opendid+"&format=json";
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            //Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
           /* for (String key : map.keySet()) {
                System.out.println(key + "--->" + map.get(key));
            }*/
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        //去掉字符串中的反斜杠\和空格
        String rsFormat=result.replaceAll("\\\\", "").replaceAll(" ", "");
        //将字符串格式化为数组
        String[] rsArray=rsFormat.split("");
        /**
         * 算法思想
         * 根据测试,在返回的数据中,QQ头像的url地址在figureurl_qq_1后,且不同QQ用户的头像地址的长度固定,均为69
         * 于是便可设计算法,先去掉"\"和空格后,利用test字符串作为辅助字符串,test=test+rsArray[i];,当test内包含"
         * figureurl_qq_1"时,记录此时test的长度,往后延长三位便是头像地址的信息开头,即http://......,此时结束循环
         * 利用subString(startindex,startindex+69)截取到url,返回
         * 
         */

        String auxiliaryString="";
        int startindex=0;
        for(int i=0;i<rsArray.length;i++){
            auxiliaryString=auxiliaryString+rsArray[i];
            if(auxiliaryString.contains("figureurl_qq_1")){
                startindex=test.length()+3;
                break;
            }
        }
        //释放资源
        auxiliaryString=null;
        rsArray=null;
        return rsFormat.substring(startindex,startindex+69);

    }

接下来是控制层代码,由于实现业务简单,所以只有一个Controller

package com.wuning.web;

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.qq.connect.QQConnectException;
import com.qq.connect.oauth.Oauth;
import com.wuning.enity.User;
import com.wuning.service.UserLoginServiceImp;
@Controller
public class mainController {
    @Autowired
    private UserLoginServiceImp userLoginServiceImp;
    /**
     * 首页请求
     * @return
     */
    @RequestMapping(value="/homepage")
    public String homePage() {
        return "main";
    }
    /**
     * 处理QQ登录请求
     * 1.设置响应格式
     * 2.将请求重定向至QQ登录授权页面
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value="/qqlogin",method=RequestMethod.GET)
    public void tologin(HttpServletRequest request, HttpServletResponse response) throws IOException{
        response.setContentType("text/html;charset=utf-8");
        try {
            response.sendRedirect(new Oauth().getAuthorizeURL(request));
        } catch (QQConnectException e) {
            e.printStackTrace();
        }
    }
    /**
     * 处理QQ登录成功后回调请求
     * 1.根据请求后回调地址后参数解析出openid 
     * 2.根据openid构造相应用户信息
     * 3.判断用户是否为已经注册用户
     * 4.如果是已经注册用户,则直接保存用户到session中,重定向回首页,如果未注册用户,则提示用户注册,
     *   此处是保存新用户信息到数据库中(相当于注册),然后重定向至首页
     *  核心:User user=userLoginServiceImp.getUserByOAuthOfQQ(request);
     * @param request
     * @return String
     * @throws QQConnectException
     * @throws IOException
     */
    @RequestMapping(value="/qqloginback")
    public String loginback(HttpServletRequest request)throws QQConnectException, IOException{
        System.out.println("请求地址:"+request.getQueryString());


        User user=userLoginServiceImp.getUserByOAuthOfQQ(request);
        //此时如果将用户信息全部存于session中,是不安全的,希望在具体应用时,只需要将需要展示的用户信息的经过包装的用户对象存于session中
        //此处是为了简单起见
        request.getSession().setAttribute("user", user);
        int count=userLoginServiceImp.getMatchCountByUserTpaId(user.getUser_tpa_openid());
        System.out.println(count);
        //如果用户已经注册
        if(count==1){
            //返回首页
            return "redirect:homepage";
        }
        else {
            //否则保存用户信息到数据库中
            userLoginServiceImp.saveNewUser(user);
            //添加具体的业务代码,如记录到日志中
            //。。。。。。。。。
            //或者将用户信息保存到ModelAndView中,到注册页将信息中取出来,避免用户二次输入
            //ModelAndView modelAndView=new ModelAndView();
            //modelAndView.setViewName("redirect:register");
            //modelAndView.addObject("user", user);
            //return modelAndView;

            //直接返回到首页
            return "redirect:homepage";
        }



    }
    /**
     * 处理用户注销请求
     * 1.将用户对象从session中移除
     * 2.重定向至首页
     * @param session
     * @return
     */
    @RequestMapping(value="/qqloginOut")
    public String qqloginOut(HttpSession session){
        session.removeAttribute("user");
        return "redirect:homepage";
    }

}

mainController说明
1.主要有三个处理请求的方法,
1.1 homePage() 请求url为:”/homepage”,处理首页请求,即在浏览器输入:你申请的域名/项目名称/homepage,如:www.zhouxuewen.iego/wuning/homepage即可浏览该项目首页
1.2 tologin() 请求url为:/qqlogin”,当用户点击登录按钮后,向本地服务器发送此请求,tologin()接收请求后,将请求重定向至QQ登录的授权页面。
页面的登录按钮


1.3 loginback() 请求url为:”/qqloginback”当QQ用户在授权页面点击登录后,页面会自动将地址重定向为你申请appid时所填的回调地址,回调地址后已经携带了获取openid的参数信息,并向本地服务器发起http请求,请求被 loginback()接收后处理。利用User user=userLoginServiceImp.getUserByOAuthOfQQ(request)获取用户信息,并到数据库中查询判断该用户是否为第一次登录,若为第一次登录,则保存用户信息到数据库中,否则重定向回首页
此时QQ登录的回调地址则为:你申请的域名/项目名称/qqloginback,这个地址也是你必须要填入qqconnectconfig.properties
和QQ互联管理中心的应用回调地址中,如我的回调地址为:http://www.zhouxuewen.iego/wuning/qqloginback.
这个地址必须在入qqconnectconfig.properties文件和管理中心的应用回调地址和Controller的处理请求的回调地址保持一致,否则将会出现请求地址错误的情况。
1.4 登录后的用户的注销操作
项目运行时效果如下:



关于项目的代码,我也会分享到csdn,这次是QQ登录的,下次将会继续退出新浪微博登录的项目,敬请期待!

本文标签: 框架教程Springqq