第三方登錄接入-qq,weibo-java

開發之前

需求:網站接入qq,sina微博登錄,本文最后付效果圖:

說明:大部分網站本身是需要用戶概念的,很多操作依附于用戶,而qq或微博作為一種登錄方式指向用戶而已,我參考了一下其他網站的做法,

一般有如下兩種做法:

1,強制綁定:用戶第一次通過qq登錄時必須與該網站賬戶綁定,也就是用戶必須要先有一個此網站賬戶才能登錄成功

2,互相獨立,用戶第一次通過qq登錄時直接重新為用戶注冊一個賬戶,如以用戶名為qq_123456直接注冊一個賬戶,與其他賬戶無關;

?

站在用戶角度考慮下,可能需要更多的選擇性,因此我是如下考慮的:

用戶登錄后在個人中心中也可設置綁定。

---------------------------------------------------------------------------------------------------

文檔說明

現在大部分第三方的登錄OAuth2.0為標準,所以開發流程基本都一致,一般都是一下步驟:

1,申請接入,獲取appid&appkey(接入后又第三方發放)

2,用戶登錄第三方下發token,

3,通過token獲取用戶唯一標示,一般是一個openId

api地址:

qq:http://wiki.connect.qq.com/api列表

sina:http://open.weibo.com/wiki/授權機制

qq&sina也提供了java sdk

https://github.com/sunxiaowei2014/weibo4j-oauth2-beta3.1.1/

http://qzonestyle.gtimg.cn/qzone/vas/opensns/res/doc/qqConnect_Server_SDK_java_v2.0.zip

sina的雖然開源了,但里面很多代碼寫的有問題,用的之后需要注意

------------------------------------------------------------------------------------------------------------

開發

數據結構方面需要加以一張表用來維護登錄方式和用戶關聯(通過openId以及登錄方式確定唯一性)

網站引入,appid,appkey,回調地址的配置有不再贅述了

代碼基本上參照sdk中的demo就可以了,

簡單貼一下controller(springMVC架構)中的代碼吧

AUthController為父類,存放一些第三方登錄的通用方法,BindController為用戶綁定提供方法,第三方登錄的controller基本上就是一個登錄跳轉方法,一個回調方法,以及一些接口api的調用

public abstract class AuthController extends BaseController {@Resourceprivate JavaMailSender mailSender;@Resourceprivate IBAuthService authService;protected LoginUser getU(BAuth auth){LoginUser loginUser= new LoginUser();loginUser.setAccessToken(auth.getAccessToken());loginUser.setIcon(auth.getIcon() == null ? IPortalConstants.defaultIconUrl: auth.getIcon());loginUser.setId(auth.getUser().getId());loginUser.setLoginType(auth.getType());loginUser.setNickName(auth.getNickName() == null ? auth.getUser().getNickName() : auth.getNickName());loginUser.setOpenId(auth.getOpenId());return loginUser;}protected LoginUser getU(User user){LoginUser loginUser= new LoginUser();loginUser.setIcon(user.getIcon() == null ? IPortalConstants.defaultIconUrl: user.getIcon());loginUser.setId(user.getId());loginUser.setLoginType(AuthType.bresume.getCode());loginUser.setNickName( user.getNickName());return loginUser;}protected boolean setUser2Session(BAuth auth){LoginUser loginuser = this.getU(auth);SessionContextHolder.getSession().setAttribute(IPortalConstants.SESSION_KEY_LOGIN_USER, loginuser);return true;}protected boolean setUser2Session(User user){LoginUser loginuser = this.getU(user);SessionContextHolder.getSession().setAttribute(IPortalConstants.SESSION_KEY_LOGIN_USER, loginuser);return true;}protected void sendRegisterMail(User user,String code) {PropertiesLoader loader = new PropertiesLoader("mail.properties");Map<String, Object> map = new HashMap<String, Object>();Email email = new Email();email.setSender(loader.getProperty("mail.from"));email.setAddress(user.getEmail());email.setSubject(loader.getProperty("mail.register.success.subject"));// 從模板生成HashMap<String, Object> param = new HashMap<String, Object>();param.put("userName", user.getUserName());param.put("userId", user.getId());param.put("code", code);email.setContent(MailUtils.getMailText(param,loader.getProperty("mail.register.success.content")));map.put("email", email);MailUtils.sendMailByAsynchronousMode(map, mailSender);}protected String callBack(Model model,BAuth newAuth){BAuth oldAuth = authService.findOne(newAuth.getOpenId(),newAuth.getType());if (oldAuth != null && oldAuth.getUser() != null) {// 判定有登錄記錄//刷新accessToken
            oldAuth.setAccessToken(newAuth.getAccessToken());oldAuth.setExpiresIn(newAuth.getExpiresIn());oldAuth.setIcon(newAuth.getIcon());oldAuth.setNickName(newAuth.getNickName());oldAuth.setRefreshAccessTime(new Date());authService.update(oldAuth);this.setUser2Session(oldAuth);return "redirect:/index";} else if(oldAuth==null) {// 判定首次登錄,記錄oldAuth = new BAuth();oldAuth.setAccessToken(newAuth.getAccessToken());oldAuth.setExpiresIn(newAuth.getExpiresIn());oldAuth.setCreatedTime(new Date());oldAuth.setIcon(newAuth.getIcon());oldAuth.setNickName(newAuth.getNickName());oldAuth.setOpenId(newAuth.getOpenId());oldAuth.setRefreshAccessTime(new Date());oldAuth.setType(newAuth.getType());authService.save(oldAuth);//用戶綁定,跳轉頁面model.addAttribute("openId", newAuth.getOpenId());model.addAttribute("loginFrom", newAuth.getType());return "site/bindAuth.jsp";}else{// 登錄過但因某種原因為綁定賬戶
            oldAuth.setAccessToken(newAuth.getAccessToken());oldAuth.setExpiresIn(newAuth.getExpiresIn());oldAuth.setIcon(newAuth.getIcon());oldAuth.setNickName(newAuth.getNickName());oldAuth.setRefreshAccessTime(new Date());authService.update(oldAuth);//用戶綁定,跳轉頁面model.addAttribute("openId", newAuth.getOpenId());model.addAttribute("loginFrom", newAuth.getType());return "site/bindAuth.jsp";}}}
AuthController
@RequestMapping("/")
@Controller
public class BindController extends AuthController {@Resourceprivate IUserService userService;@Resourceprivate IBAuthService authService;@Resourceprivate IUserVerifiedService verifiedService;@Resourceprivate JavaMailSender mailSender;@RequestMapping("/ingore-bind")public String ingore_bind(@RequestParam(value = "loginFrom", required = true) Integer loginFrom,@RequestParam(value = "openId", required = true) String openId,ModelMap model, HttpServletResponse response) {BAuth auth = authService.findOne(openId, loginFrom);if (auth == null) {return "404";}if (auth.getUser() == null) {User user = new User();/** user.setUserName(userName); user.setPassword(password);*/// user.setEmail(email);
            user.setNickName(auth.getNickName());user.setIcon(auth.getIcon());user.setRegisterType(AuthType.fromCode(loginFrom).getRt().getType());user.setType(UserType.PERSIONAL.getCode());user.setLevel(0);userService.registerFromAuth(user);auth.setUser(user);authService.save(auth);}this.setUser2Session(auth);return "redirect:/index";}@RequestMapping("/login-bind")public @ResponseBody JSONObject bind(@RequestParam(value = "loginFrom", required = true) Integer loginFrom,@RequestParam(value = "openId", required = true) String openId,@RequestParam(value = "email", required = true) String email,@RequestParam(value = "password", required = true) String password,ModelMap model, HttpServletResponse response) {BAuth auth = authService.findOne(openId, loginFrom);if (auth == null) {return this.toJSONResult(false,"404");}if (auth.getUser() == null) {try {// 登陸校驗User user = userService.loginCheck(email, password);auth.setUser(user);authService.update(auth);} catch (CoreException e) {if (e.getErrorCode() == PortalErrorCode.USER_PASSWORD_ERROR_TIMES_EXCEED_ERROR) {return this.toJSONResult(false,this.getMessage(e, e.getArgs()));} else {return this.toJSONResult(false, this.getMessage(e));}}}this.setUser2Session(auth);return this.toJSONResult(true);}@RequestMapping("/regist-bind")public @ResponseBody JSONObject registBind(@RequestParam(value = "loginFrom", required = true) Integer loginFrom,@RequestParam(value = "openId", required = true) String openId,@RequestParam(value = "email", required = true) String email,@RequestParam(value = "password", required = true) String password,ModelMap model, HttpServletResponse response) {BAuth auth = authService.findOne(openId, loginFrom);if (auth == null) {return this.toJSONResult(false);}if (auth.getUser() == null) {User user=new User();
//            user.setUserName(userName);
            user.setPassword(password);user.setEmail(email);try {user.setRegisterType(RegisterType.PORTAL_REGISTER.getType());user.setType(UserType.PERSIONAL.getCode());user.setLevel(0);user.setNickName(auth.getNickName());user.setIcon(auth.getIcon());userService.register(user);//生成郵箱驗證碼UserVerified uv = new UserVerified(user);verifiedService.save(uv);// 發送注冊成功的郵件if (CommonUtils.isNotEmpty(user.getEmail())) {sendRegisterMail(user,uv.getCode());}} catch (CoreException e) {return this.toJSONResult(false, this.getMessage(e));}auth.setUser(user);authService.save(auth);}this.setUser2Session(auth);return this.toJSONResult(true);}}
BindController
@RequestMapping("/")
@Controller
public class QQController extends AuthController {@Resourceprivate IBAuthService authService;@Resourceprivate IUserService userService;@RequestMapping("/qqlogin")public void index(HttpServletRequest request, HttpServletResponse response,Model model) throws IOException {response.setContentType("text/html;charset=utf-8");try {response.sendRedirect(new Oauth().getAuthorizeURL(request));LOGGER.info("login by qq");} catch (QQConnectException e) {e.printStackTrace();}}@RequestMapping("/qq_callback")public String callback(HttpServletRequest request,HttpServletResponse response, Model model) {try {AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);String accessToken = null, openID = null;long tokenExpireIn = 0L;if (accessTokenObj.getAccessToken().equals("")) {LOGGER.error("QQ Login failed,caused by 沒有獲取到響應參數");return "404";}accessToken = accessTokenObj.getAccessToken();tokenExpireIn = accessTokenObj.getExpireIn();LOGGER.info("Get accessToken from qq,accessToken:" + accessToken+ ",tokenExpireIn" + tokenExpireIn);// 利用獲取到的accessToken 去獲取當前用的openidOpenID openIDObj = new OpenID(accessToken);openID = openIDObj.getUserOpenID();LOGGER.info("利用獲取到的accessToken:" + accessToken+ ", 去獲取到當前用戶openid:" + openID + ".");String icon = null, nickName = null;// 去獲取用戶在Qzone的昵稱等信息UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();if (userInfoBean.getRet() == 0) {nickName = userInfoBean.getNickname();// userInfoBean.getGender();
icon = userInfoBean.getAvatar().getAvatarURL30();// userInfoBean.getAvatar().getAvatarURL50();// userInfoBean.getAvatar().getAvatarURL100();} else {LOGGER.error("很抱歉,我們沒能正確獲取到您的信息,原因是:" + userInfoBean.getMsg());}BAuth newAuth = new BAuth();newAuth.setAccessToken(accessToken);newAuth.setExpiresIn(tokenExpireIn);newAuth.setIcon(icon);newAuth.setNickName(nickName);newAuth.setOpenId(openID);newAuth.setType(AuthType.QQ.getCode());return this.callBack(model, newAuth);// 通過openid判斷首次登錄與否/*    BAuth bauth = authService.findOne(openID, AuthType.QQ.getCode());if (bauth != null && bauth.getUser() != null) {// 判定有登錄記錄//刷新accessTokenbauth.setAccessToken(accessToken);bauth.setExpiresIn(tokenExpireIn);bauth.setIcon(icon);bauth.setNickName(nickName);bauth.setRefreshAccessTime(new Date());authService.update(bauth);this.setUser2Session(bauth);return "redirect:/index";} else if(bauth==null) {// 判定首次登錄,記錄bauth = new BAuth();bauth.setAccessToken(accessToken);bauth.setCreatedTime(new Date());bauth.setExpiresIn(tokenExpireIn);bauth.setIcon(icon);bauth.setNickName(nickName);bauth.setOpenId(openID);bauth.setRefreshAccessTime(new Date());bauth.setType(AuthType.QQ.getCode());authService.save(bauth);//用戶綁定,跳轉頁面model.addAttribute("openId", openID);model.addAttribute("loginFrom", AuthType.QQ.getCode());return "site/bindAuth.jsp";}else{// 登錄過但因某種原因為綁定賬戶bauth.setAccessToken(accessToken);bauth.setExpiresIn(tokenExpireIn);bauth.setIcon(icon);bauth.setNickName(nickName);bauth.setRefreshAccessTime(new Date());authService.update(bauth);//用戶綁定,跳轉頁面model.addAttribute("openId", openID);model.addAttribute("loginFrom", AuthType.QQ.getCode());return "site/bindAuth.jsp";}*/} catch (QQConnectException e) {e.printStackTrace();}return "redirect:/index";}@RequestMapping("/qqss")public void talk(HttpServletRequest request, HttpServletResponse response,Model model) throws IOException {response.setContentType("text/html;charset=utf-8");request.setCharacterEncoding("utf-8");String con = request.getParameter("con");HttpSession session = request.getSession();String accessToken = (String) session.getAttribute("demo_access_token");String openID = (String) session.getAttribute("demo_openid");System.out.println(accessToken);System.out.println(openID);// 請開發者自行校驗獲取的con值是否有效if (con != "") {Topic topic = new Topic(accessToken, openID);try {GeneralResultBean grb = topic.addTopic(con);if (grb.getRet() == 0) {response.getWriter().println("<a href=\"http://www.qzone.com\" target=\"_blank\">您的說說已發表成功,請登錄Qzone查看</a>");} else {response.getWriter().println("很遺憾的通知您,發表說說失敗!原因: " + grb.getMsg());}} catch (QQConnectException e) {System.out.println("拋異常了?");}} else {System.out.println("獲取到的值為空?");}}
}
QQController
@RequestMapping("/")
@Controller
public class SinaController extends AuthController {@Resourceprivate IBAuthService authService;@Resourceprivate IUserService userService;@RequestMapping("/sinalogin")public void index(HttpServletRequest request, HttpServletResponse response,Model model) throws IOException {response.setContentType("text/html;charset=utf-8");try {response.sendRedirect(new Oauth().authorize("code"));LOGGER.info("login by weibo");} catch (WeiboException e) {e.printStackTrace();}}@RequestMapping("/weibo_callback")public String callback(HttpServletRequest request,HttpServletResponse response, Model model) throws IOException {try {Oauth oauth = new Oauth();String code = request.getParameter("code");LOGGER.info("code: " + code);AccessToken accessTokenObj = oauth.getAccessTokenByCode(code);if (accessTokenObj == null) {LOGGER.error("AccessToken 獲取失敗,code:" + code);}String accessToken = accessTokenObj.getAccessToken();String openId = accessTokenObj.getUID();String expireInStr = accessTokenObj.getExpireIn();Users um = new Users(accessToken);User user = um.showUserById(openId);LOGGER.info(user.toString());BAuth newAuth = new BAuth();newAuth.setAccessToken(accessToken);newAuth.setExpiresIn(expireInStr != null ? Long.parseLong(expireInStr) : 3600);newAuth.setIcon(user.getAvatarLarge());newAuth.setNickName(user.getScreenName());newAuth.setOpenId(openId);newAuth.setType(AuthType.SINA.getCode());return this.callBack(model, newAuth);} catch (WeiboException e) {if (401 == e.getStatusCode()) {LOGGER.error("Unable to get the access token.");} else {e.printStackTrace();}}return "redirect:/index";}}
SinaController

?

-------------------------------------------------------------------------------------------------------------

頁面效果

注:該流程為用戶首次使用第三方登錄時流程

1,登錄頁面放置第三方登錄圖標

2,點擊圖標接入第三方接口,可跳轉至第三方登錄界面

3,第三方登錄完成,用戶賬戶綁定

4,用戶登錄后,可在個人設置中管理第三方登錄的綁定

?

轉載于:https://www.cnblogs.com/china2k/p/4217108.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257789.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257789.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257789.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python替換img的路徑為新的路徑_以“五智”為核心 南寧電信打造5G時代數字家庭新路徑...

來源&#xff1a;通信信息報本報訊(特約記者 許輝堅)近日&#xff0c;中國電信廣西南寧分公司在協助廣西自治區通信管理局主辦的“電信用戶委員會體驗活動”中&#xff0c;以發揮用戶委員會的平臺和紐帶作用&#xff0c;促進持續改善電信服務質量為主題&#xff0c;以“五智”能…

0118——RTLabel和正則表達式

RTLabel和RegexKitLite都要導入第三方庫 使用Regexkitlite庫進行正則表達式的解析 1.庫是使用MRR&#xff0c;如果在ARC工程里面使用這個類&#xff0c;必須在project->build phases->compile resources里面將regexKitLite.m的編譯指令設為&#xff1a;-fno-objc-arc 2.需…

熱帶雨林繪畫軟件測試,兒童畫教程|色彩練習與思維創想——好熱鬧的熱帶雨林!...

課程類型綜合創意繪畫課程參考課時90分鐘工具材料勾線筆、水彩筆、卡紙課程構思小朋友們知道嗎&#xff1f;熱帶雨林是地球上抵抗力和穩定性最高的生態系統&#xff0c;常年氣候非常的炎熱&#xff0c;雨量充沛&#xff0c;沒有明顯的季節差異&#xff0c;生物群落演替速度極快…

對于一個IE8兼容性問題的反思

近期做了一個需求&#xff0c;功能非常easy&#xff0c;把用戶的優惠券數量讀取出來&#xff0c;然后顯示到“用戶中心”上。開發完畢后。別的瀏覽器正常。可是到IE8上就不行了。并且&#xff0c;按下F12之后&#xff0c;就又能夠載入出來了。首先&#xff0c;找了前端人員&…

Grunt + Bower—前端構建利器

目前比較流行的WEB開發的趨勢是前后端分離。前端采用重量級的Javascript框架&#xff0c;比如Angular&#xff0c;Ember等&#xff0c;后端采用restful API的Web Service服務&#xff0c;通過JSON格式進行數據交互。 對于后端服務語言來說&#xff0c;不論是Ruby的rake&#xf…

apache服務器性能診斷,Apache服務器性能評測

。51Testing軟件測試網m#z"fX}0H:P{(bHP~bd7h5z7I(Sn3H01.比較現有T2000 Apache2.2.8經過優化前后的效果51Testing軟件測試網 R4VsR^4MO!G7fWebserver IP&#xff1a;10.56.234.3151Testing軟件測試網e{]Q/\(p|優化前httpd.conf&#xff1a;da*Z"[d0----------------…

Linux命令行編輯快捷鍵

2019獨角獸企業重金招聘Python工程師標準>>> ctrl ? 撤消前一次輸入 ctrl c 另起一行 ctrl r 輸入單詞搜索歷史命令 ctrl u 刪除光標前面所有字符相當于VIM里d shift^ ctrl k 刪除光標后面所有字符相當于VIM里d shift$ 刪除 ctrl d 刪除光標所在位置上的字符…

kali裝電腦_Kali Linux可以安裝到平板電腦嗎?

在用Windows的電腦上克隆Kali插入U盤.運行Win32 Disk Imager.選擇Kali Linux ISO文件作為被克隆的文件,然后核實要克隆的U盤是否正確.克隆完成后,從Windows機器安全彈出U盤.現在你可以用U盤啟動Kali Linux了.在用Linux的電腦上克隆Kali在Linux環境下制作可啟動的Kali Linux U盤…

思科查看服務器啟動配置文件,啟動配置檢查UCS

本文解釋如何使用UCS將啟動功能和命令迅速執行配置狀態檢查。UCS將啟動功能允許用戶迅速執行一粗略檢查為了保證刀片適當地配置允許BIOS繼續。意志啟動配置檢查是驗證CPU和DIMM配置。此檢查迅速幫助用戶調試啟動問題。思科UCS在意志啟動配置檢查提供幾個工具幫助。這些工具包括…

lnmp下配置虛擬主機

一&#xff1a;首先熟悉幾個命令 which php ---> which是通過 PATH環境變量到該路徑內查找可執行文件&#xff0c;所以基本的功能是尋找可執行文件 whereis php ----> 將和php文件相關的文件都查找出來 service php-fpm/nginx/mysqld restart 重啟服務 二&…

AssetBundle.CreateFromFile的有趣事情

有趣的事情發生了&#xff1a; [MenuItem("AssetBundles/Build AssetBundles")] staticvoid BuildABs () { AssetBundleBuild[] buildMap new AssetBundleBuild[1]; buildMap [0].assetBundleName "test.assetbundle";//打包的資源包名稱 string[] resou…

[cocos2dx筆記010]用于UI的事件管理器

cocos2dx有一個編輯器&#xff1a;cocostudio。眼下來說&#xff0c;已經是比較好用了。僅僅要載入導出的資源。就能夠用上了。省去手動搭建面的麻煩。可是。非常多須要事件的地方&#xff0c;操作比較麻煩&#xff0c;所以這里提供一個事件管理器來集中和簡化管理事件。對于C事…

異形3×3魔方還原教程_【理論篇】三階魔方4.33千億億種變化是怎么計算出來的?...

本篇文章主要介紹三階魔方總狀態數是如何計算出來的&#xff0c;并介紹了兩種算法&#xff0c;盡量保證語言通俗易懂&#xff0c;不涉及高深的理論知識&#xff08;當然我也不懂&#xff1a;P&#xff09;一、4.33千億億到底有多大&#xff1f;我們都知道三階魔方的總變化狀態數…

Jquery 對話框確認

$("#aa").click(function(){if(confirm("是否繼續")){$(#aa).fadeOut(500);} }) 轉載于:https://www.cnblogs.com/chen-lhx/p/5149469.html

datazen Active Directory AD 配置

今天苦心經營的datazen 鏈接AD&#xff0c;文檔已經無法吐槽了簡單的幾句話&#xff0c;根本不夠用。 先說一下鏈接AD 的好處吧&#xff0c; 1 首先免去設置密碼的麻煩&#xff0c;因為直接用AD賬號的密碼。 2 更安全&#xff0c;因為客戶可不想自己的自己的系統&#xff0c;開…

Android CardView卡片布局 標簽: 控件

CardView介紹 CardView是Android 5.0系統引入的控件&#xff0c;相當于FragmentLayout布局控件然后添加圓角及陰影的效果&#xff1b;CardView被包裝為一種布局&#xff0c;并且經常在ListView和RecyclerView的Item布局中&#xff0c;作為一種容器使用。CardView應該被使用在顯…

櫥柜高度與身高對照表_下一套房子裝修,櫥柜就照這樣打,布局尺寸這么詳細,不信不好用...

閑在家的時候&#xff0c;動手給自己做一頓色香味俱全的美食&#xff0c;是一個享受的過程。享受的&#xff0c;不僅僅是味蕾的體驗&#xff0c;擇菜、洗菜、切菜、下鍋...每一個環節都是。不過&#xff0c;這取決于你是否有一個好廚房&#xff1b;而廚房最最最重要的家具&…

DOSbox匯編集成環境下的具體設置

altenter能夠全屏幕&#xff0c;假設認為游戲執行速度不合適&#xff0c;能夠改動 cycles3000 。將3000適當調整大小。 3。執行 DOSBox&#xff0c;會打開兩個 DOS 窗體。我們僅僅需在例如以下窗體中鍵入 mount c h:\pal 此命令的作用為將 h:\pal 掛載為 C 盤&#xff0c;h:\p…

.NET手記-JS獲取Url參數

最近為App做活動專區&#xff0c;其中很多活動都是采用html 5頁面來制作的。一方面體量較小&#xff0c;制作快速&#xff0c;更新維護容易&#xff1b;另一方面&#xff0c;嵌入App后適配效果也不會很差。 這里我們采用混編形式來從native app傳參給web頁面&#xff0c;我們采…

Entity Framework系列之DataBase First

第一步 新建數據庫和表 USE [TestDB] GO /****** Object: Table [dbo].[T_User] Script Date: 01/14/2015 20:27:52 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[T_User]([Id] [int] IDENTITY(1,1) NOT NULL,[Name] [nvarchar](50) NUL…