新闻中心

01-17
2018
我用Python玩小游戏“跳一跳”,瞬间称霸了朋友圈!
从前几天微信最新版本 6.6.1 的更新开始,微信小程序游戏“跳一跳”似乎在一夜之间风靡了朋友圈。它甚至比五六年前的飞机大战游戏都火爆,这种小游戏的火爆不仅仅是因为有魔性、有意思,更重要的是可以进行好友 PK!“跳一跳”的小游戏推出后,很多准备奋发向上的同学,这个假期的美好愿景被毁了。为了多跳几步,以及朋友圈的排名,大家在整个假期都是这样的:就这样跳啊跳...挤地铁跳,蹲马桶跳,乘电梯跳,静默的每 1 秒都不能浪费在办公室,还要时刻警觉后面...说好的工作呢...我控制不住我自己啊!可是很多人费尽心思跳了一下午也没超过 100 分但排行榜里四分之三的人都超过三位数了……真是扎心了……今天小编来告诉你,如何才能获取高分,如何才能占据朋友圈榜首?游戏攻略拿高分普通版本的高分秘籍是这样的:如果你每次都能挑到各自的正中间的话,可以 + 2 分,如果连着跳到中间会 + 4、+6、+8、+10……跳到污水井盖上面,停留 2 秒,等到下水道声音响起直接 + 5 分跳到魔方上面,停留 2 秒,等到魔方转正会直接 + 10 分跳到音乐盒上面,停留 2 秒,等到音乐响起会直接 + 30 分跳到便利店,停留 2 秒,等到便利店开门会直接 + 15 分以上是针对普通用户,但对咱们程序猿来说用这套太 Low 了,接下来要说的是如何从技术层面去实现高分:技术手段实现高分通过 Python 手段在 Github 上面已经有人用 Python 来玩跳一跳这个游戏了,想多少分就有多少分。GitHub 地址:https://github.com/wangshub/wechat_jump_game步骤:安卓手机打开 USB 调试,设置》开发者选项》USB 调试。电脑与手机 USB 线连接,确保执行 adb devices 可以找到设备 id。界面转至微信跳一跳游戏,点击开始游戏。运行 python wechat_junp_auto.py,如果手机界面显示 USB 授权,请点击确认。很有趣!简单点说就是:用电脑帮你玩微信跳一跳,全自动,不用手动。效果:这里梳理一份稍微完整一点的操作步骤,以 Mac 的为例,Win 的思路是一样的。另外,这里用的是安卓手机,iOS 也差不多,不过要下载一个 5.5GB 的 Xcode。1、下载程序,打开下面的链接,点右侧 clone or download,再点 download zip。2、解压 zip 文档,再把文件夹挪到桌面,打开文件夹,你会看到很多东东:3、打开 mac 系统自带的“终端”,这是一个命令行应用,win 用 cmd 就可以了吧。4、通过终端进入文件夹,命令行如下:~/Decktop/wechat_jump_game-master5、安装 pip,在终端输入 sudo easy_install pip 再回车,可能要输入密码。6、安装各种依赖程序,在终端输入 pip install -r requirements.txt 再回车,系统会自动安装。requirements.txt 就是文件夹里的一个 txt 文档,里面写着会自动安装哪些程序。pip 就是第 5 步安装的程序,如果没安装,pip install -r requirements.txt 将无法执行。7、安装 adb,打开下面的链接查看,有 3 种方法,建议用第二种,是英文,如果你不懂英文可以百度中文教程。https://stackoverflow.com/questions/31374085/installing-adb-on-mac-os-x8、打开安卓手机的设置 - 开发者选项 - USB 调试(如果没有开发者选项,可百度打开开发者选项的方法),用 USB 线连接手机和电脑,手机可能会弹出对话框,点同意。如果出现运行脚本后小人不跳的情况,请检查是否有打开“USB 调试(安全模式)”,记得顺便打开 USB 模拟点击。9、在终端输入 adb devices,如果看到下面这种信息,说明 adb 已正确安装,也说明电脑成功检测到手机。如果你系统是 Win10 或 Win8 可能需要先设置一下“禁用强制驱动程序签名”。不然会出现下面的“文件的哈希值不在指定目录中”安装不上 adb 驱动的问题,网上有教程请自行学习。10、打开微信跳一跳点开始,在终端输入 python wechat_jump_auto.py 点回车,游戏就会自动开始~ 请根据手机分辨率运行相应的 *.py 文件。注意:我跳了很多次,最后都会掉下盒子,暂时最多只能跳到 1800+ 分,不能一直跳下去。分辨率不同,配置文件也不一样,具体看 config 这个文件夹。别刷太高分,有人刷到 4000,结果分数被微信清零。实验结果:只要有耐心,你就是王者下面分析一下代码,Main 部分有一个 While 循环,只要你不终止,它会一直重复操作。Main部分代码里面主要调用的自定义函数有三个,还有一个 time.sleep 是为了延迟一下:pull_screenshot() #获取图像find_piece_and_board(im) #根据图像获取两个点的坐标值jump(math.sqrt((board_x - piece_x) ** 2 + (board_y - piece_y) ** 2))#根据两点距离和手机像素计算按压时间并 JUMPpull_screenshot()这个函数主要是利用 adb 来获取图像,这里顺便说一下“adb”,adb 是连接 Android 手机与 PC 端的桥梁,可以让用户在电脑上对手机进行全面的操作。借助 adb 工具,我们可以管理设备,还可以进行如安装软件、系统升级、运行 Shell 命令等等操作。如“pull”就是获取设备中的文件,想更多了解 ADB 请自行学习~find_piece_and_board()根据图像获取当前小人位置和落点的坐标系(piece_x, piece_y, board_x, board_y),这个是这个脚本中的核心部分。jump根据设定的“长按的时间系数”计算需要的按压时间,这个系数是根据手机分辨率推出来的,按压时间设定不小于 200ms,核心命令是 adb 的“input swipe”。“input swipe”模拟的是手指在屏幕上的滑动事件,如果两个点坐标不变化就成了长按了。代码中四个变量的设置是:“swipe_x1,swipe_y1,swipe_x2,swipe_y2 = 320,410,320,410”,所以是模拟的长按,其实滑动也是可以的。伪造 POST 请求刷分除了可以用 Python 实现高分,还有网友爆料还可以直接伪造 POST 请求刷分,直接改分数。昨日,V2EX 网站上一篇题为《微信跳一跳 可以直接更改分数, POST 请求没有校验… 》的文章获得大量曝光,帖中指出微信小程序存在漏洞,跳一跳小游戏可以直接改分数。用户朱鹏飞根据帖子的指引,发现甚至连微信小程序、小游戏的源代码都可以直接下载,只需要知道 appid 和版本号,就可以直接构造 URL 下载后缀为 wxapkg 的源码包,不需要任何验证。据微信公众号“小专栏平台”消息,截自 1 月 1 日 23:50,微信官方已经修复了这个漏洞。不过,据说一些老版本的微信还是可以抓包获取包地址。最后一个微信已经修复 Bug(部分版本没有修复),但只要利用好前面两个攻略,再配合对节奏的把握,登上朋友圈前几完全不在话下。话不多说,赶紧去玩吧!!!
01-17
2018
WebAPI 实现前后端分离
随着Web技术的发展,现在各种框架,前端的,后端的,数不胜数。全栈工程师的压力越来越大。现在的前端的框架,既可以做各种Web,又可以做各种APP,前端框架更新换代越来越快,越来越多。传统的模式前端和后端进行调试,修改都非常麻烦。往往前端配合后端很痛苦,后端也嫌前端麻烦。(无解,能动手解决的事,尽量别动嘴。办公室应该常备一些,绷带,止血条,速效救心丸等药品。为了阻止事态升级,办公室要加强刀具管制条例。)前后端分离前端根据事先约定好的文档,可以自己摸拟数据,然后开发,测试,调试UI,发布到线上时把API接口改成线上API接口,即可完事。前端日后增加新功能,修改UI,自己修改,自己编译更新自己UI站点,发布线上只要调上线上API接口即可。并不需要麻烦到后端。两者工作进行分离。后端需要跟前端商量好接口,写好接口文档,在接口功能上相互沟通(其实相当于需求相互沟通),一旦接口文档订好之后,只需按事先约定实现API接口即口。把项目编译好发布到线上服务器。即可完事。后端实现WebApi接口,还可以面对各种调用,如PC端web,手机APP,或者其它设备。一个接口多种调用,实现代码去重。工作模式分析对前端和后端进行分离。各司其职,各自在自己的领域集中精力研究。更能有效的加深技术深度。 前后端分离的模式,你需要N名前端工程师和N名后端工程师。首先我们要约定一些返回基本的格式,比如用XML,还是JSON。结果大多数前端都是喜欢JSON,因为JS天生就支持JSON。我贴出一些示例代码  {    "ResultCode": 1300,    "Message":"权限不足",    "Date":null,   }: ::::返回参数说明参数名类型是否必有说明ResultCodeint是返回码Messagestring是结果说明DetailErrorjosn否具体错误Datejosn否数据        ResultCodeResultCode说明1000成功1100服务器异常1200身份验证异常1300权限不足1400传递参数验证不通过1500版本异常1600业务逻辑异常1700系统成升级中1800该接口己弃用          具体异常这是一个有点争议的地方,有很多业务逻辑异常,出于对用户的友好提示。一些生涩难懂的错误提示,直接给到用户,用户一脸懵逼。但是后端却不能修改成友好提示,这样不方便调试,寻找问题原因。一般来讲,前端可以自动修改友好提示给用户。如果后端返回字符串,前端写死在代码中,万一,某一天后端认为这个描述更符合场景,修改的字符串。敌军还有30秒到达战场。建议:尽量使用异常代码,大家可以看到上面贴出例子,就使用的异常代码。每种异常都有唯一编号,描述可以更改。但是编号不变。用户异常(1601000)说明1601001账号/密码错误1601002账号被冰冻1601003原密码不对    版本控制 每个API都有一个版本,其实也是就针对APP,如果是WEB端的,都是直接升级的因为B/S结构本身就是存在升级方便的优势,只需要把服务端更新就可以了。版本控制一般用两种方式第一种:URL不变,版本写在HTTP标头内面。第二种:版本写在URL上面。本人推荐第二种,比较直接方便了解。示例:http://www.xxx.com/版本号当前版本号:v1 http://www.baidu.com/v1/UserSecurity/LoginAPI风格现在流行的api风格比较多,最出名的就是restful风格。按本人的经验,完全走restful风格是很困难的,可能也是水平问题,在团队内面也要考虑到其它成员的水平问题。我们目前API风格还是保留以前风格。示例,V*代表版本号http://xx.com/V*/UserSecurity/SignOutHTTP谓词使用 Post 方法在服务器上创建/修改/删除资源使用 Get 方法从服务器检索某个资源或者资源集合基本命名规则使用骆驼式命名法-大驼峰法跨域处理前端站点和后端API布署到不同的站点,就会产生跨域问题。什么是同源策略?同源是域名,协议,端口相同。也就是说如果不同,则是非同源。同源策略是浏览器的一基本的安全功能,非同源访问,浏览器会进行拒绝。HMTL上面的SRC地址,你可以指定任何URL,表单提交,你可以提交到任何URL。但是,你如果使用AJAX技术,就会受到同源策略的影响,拒绝提交。现代浏览器几乎都支持跨域资源请求的一种方式。这种技术叫CORS(跨域资源共享)CORS跨域分两种第一种,简单跨域。第二种,复杂跨域。解决方案:HTTP输出标头增加如何节点注意有前端框架版本,对安全要求较高,不能使用通配符*,要指定跨域域名。Access-Control-Allow-Origin:* 下面节点可填,可不填,根据实际情况,自行决定。123Access-Control-Allow-Methods:GET,POST,OPTIONSAccess-Control-Allow-Credentials:trueAccess-Control-Allow-Headers:根据请求头的内容,填写  注意:复杂跨域比要简单跨域麻烦,更花费性能。因为复杂跨域在请求之前会先发一个options预请求,根据响应判断服务器是否支持跨域。也就是说,实际上请求了两次。Cookies作用域不同的站点,如何通用Cookies?一般情况只需把cookies作用域设置顶级域名,浏览器会自动把cookies在访问子域名的时候捎上去。示例,访问二级域名时候,cookies默认会被传送过去。顶级域名:baidul.com cookies作用域:.baidu.com 二级域名: www.baidu.com api.baidu.com 示例下面贴一些示例文档,其它的就不多讲啦 基本上,WebApi前后端分离的细节和注意点,都记录下来,还有更多的细节,需要读者在开发过程自己去寻找答案。随笔完毕!
01-17
2018
谷歌出来走两步:Home Max可致无线路由器崩溃
1月17日消息,谷歌Home Max智能音箱已经正式发售,价格是399美元。没想到上市没有多长时间,就有该产品的用户在谷歌论坛上反馈该音响问题频频。谷歌Home Max可致无线路由器崩溃(图片来自TheVerge)       谷歌产品论坛上有了一份初步报告,称用户在使用Home Max播放音乐时,无线网络可能会产生崩溃停止工作的情况。 目前谷歌方面要求用户将含有关键字“GHT3 -无法设置最大的网络”的截图和路由器日志的情况保留,以便他们对此问题进行诊断。       对于出现的问题, 谷歌公司的发言人对此作出回应,谷歌Home Max用户反映的问题描述显示,当该用户的Home Max连接无线网络时,无线路由器就会崩溃,只能通过重启无线路由器来解决这个问题。       不过一部分用户认为,路由器的硬件配置不同可能是导致这个问题出现的原因。但自最初的用户反映该情况以后,有人证实,他们在不同的无线路由器上都遇到了同样的问题。      据了解,谷歌Home Max是一款尺寸较大的音箱。这款音箱配备了双4.5英寸低音单元和0.7英寸的高音单元。谷歌在10月份的发布会上表示,谷歌Home Max的音量要比谷歌Home大20倍,而用户可以通过Cast、蓝牙或3.5毫米接口去连接音箱。       Home Max还支持Smart Sound功能,它将会让扬声器自动适应房间尺寸,消除一些杂音。如果将音响放置在墙边或者架子上,它们会听起来不同。Smart Sound功能就能够让这些差别消除。       Home Max能够支持许多主流音乐在线平台,比如YouTube Muisc Spotify以及Google Play Muisc、Pandora等。
01-16
2018
“微信之父”张小龙透露公众号两大惊喜!
微信公众号将会单独发布app,以后会是直接对作者进行赞赏,而不是对公众号。2018微信公开课PRO版”在广州保利世贸博览馆举行,“微信之父”张小龙在主旨演讲中公布了微信公众平台的最新变化。Part1-赞赏恢复,可直接打赏作者2017年4月19日,微信方面宣布,因苹果公司新规出台,对应用内支付规则进行了变更,iOS版微信公众平台及表情平台赞赏功能从当天17:00起被关闭,安卓等其他版本微信赞赏功能不受影响。对此,张小龙在“2018微信公开课PRO版”现场表示,公众号赞赏功能会很快恢复过来。此外,还有一个改变,公众号以后会是直接对作者进行赞赏。“2017年,微信和苹果公司做了很好的合作,经过协调达成了一些共识。跟苹果公司沟通之后,我们也对自己思考了很多。之前没有把作者作为一个独立个体,以后会是直接对作者进行赞赏。对公众号打赏还是对公众号背后的作者打赏,是两个事情。”Part2-公众号出app,将实现手机端编辑目前,微信公众号的内容编辑只能在PC端实现。张小龙透露,微信公众号的app很快就会推出。他说:“公众号的app做了,但还没有发布,因为没有达到我们的预期。微信是为手机而生,但公众号后台还是在PC上生成,这点确实很奇怪。我们确实很早就应该把app推出来,但因为我们自己的问题,没出来,挺可惜的。”Part3-微信之父“跳一跳”6000分!张小龙在现场还玩起了最近大火的小程序游戏“跳一跳”,并透露自己最高分为6000多分,获得了“立地成佛”的称号。作为微信花了最多的时间来做、也是最大的项目,张小龙对“小程序”非常有信心和耐心。他说:“希望小程序一步步地长大,而不是被催肥。小程序代表一种表达的方式,未来万事万物都包含信息。小程序刚好是各种信息的载体,是人们连接信息的方式。”2017年,微信月活跃用户数达到9.8亿,微信支付用户破8亿,小程序经历数十次更新完善……作为微信一年一度最大盛会,在“2018微信公开课PRO版”上,微信2017年重点业务线阵容全面亮相,小程序、微信支付、企业微信等产品亮眼呈现。现场参会嘉宾共同回顾2017并展望2018,以全新姿态迎接崭新时代。
01-16
2018
今天是Windows 10免费升级的最后一天
1月16日消息:今天是Windows 7/8.1免费升级Windows 10的最后一天了,虽然这个“最后一天”已经不是第一次了。  微软将在明天正式关闭Windows 10免费升级通道,之后拥有正版Windows 7和Windows 8.1的用户想要升级到Windows 10,只能花钱了。Windows 10  事实上,微软在2016年7月29日就结束了正常的Windows 10免费升级通道,但为了视听障碍人士,微软的辅助技术免费升级通道一直都没有关闭。  所以,在2016年7月29日之后,人们仍然可以通过辅助技术通道免费将Windows 7和Windows 8.1升级到Windows 10。  就在上个月,微软宣布这个通道会在12月31日关闭,结果还是没能关闭成功,延期到了现在。这一次应该是真要关闭了吧?Windows 7/8.1免费升级Windows 10系统的最后一个“后门”即将于明天正式封闭。这意味着用户在今天之后将不再免费升级,今后想要升级至少需要支付119.99美元(Windows 10家庭版本)的费用。Windows 10上线之初,微软提供了长达1年的免费升级计划,无论是正版还是盗版用户在这个时间段内都可以免费升级至Windows 10。2016年7月29日免费通道关闭之后,用户发现通过“辅助技术”依然能够免费升级。辅助技术更新是Windows 10在2016年7月一年免费升级期结束后的一个“小小漏洞”。因为微软对辅助技术的定义相当宽泛,包括使用键盘快捷方式、放大镜的Win7/8.1客户都算,所以实质上几乎适用于任何人。微软最初曾表示将于2017年12月31日关闭这个漏洞,不过本月微软宣布做出调整,延长至1月16日。
01-16
2018
传爱奇艺在美提交IPO申请 融资10亿美元
1月16日消息,外媒汤森路透旗下IFR报道,百度旗下流媒体视频服务爱奇艺已秘密在美国提交了IPO(首次公开招股)申请,融资约10亿美元。对此消息,爱奇艺方面拒绝置评。传爱奇艺在美提交IPO申请(图片来自baidu)      外媒援引消息人士说法,爱奇艺IPO可能会在今年第一季度末或第二季度初完成。其实早在2017年9月,彭博社就援引两位知情人士说法,爱奇艺计划最早于2018年在美国IPO,届时的估值可能超过80亿美元。        根据百度递交给SEC的文件显示,旗下视频业务爱奇艺2016年营收112.83亿元(16.25亿美元),较2015年同期的52.95亿元增长113.1%。爱奇艺2015年营收则较2014年的28.7亿元增长84.3%。2016年,爱奇艺运营亏损27.65亿元(3.98亿美元),较2015年同期的亏损23.83亿元有所增加。不过,相比爱奇艺的营收增长,其运营亏损的增幅并不大。       公开资料显示,爱奇艺,原名奇艺,于2010年4月22日正式上线。2011,百度耗资4500万美元认购奇艺B轮优先股,并于2012年11月3日,收购原爱奇艺第二大股东普罗维登斯所持股份,成为其单一最大股东。       2013年,百度斥资3.7亿美元收购PPS,实现PPS与爱奇艺的合并,之后在自制剧,产品建设,独播等很多领域动作频繁。       2016年,百度公司发布公告称,董事会收到了来自百度董事长兼CEO李彦宏和爱奇艺CEO龚宇的非约束性提议,计划收购百度所持有的爱奇艺股份,估值28亿美元。仅仅过了几个月,百度董事长兼首席执行官李彦宏和爱奇艺首席执行官龚宇代表买方财团致信百度董事会,宣布撤回今年2月提出的爱奇艺私有化要约。
12-19
2017
小程序发布后搜索不到是怎么回事
      随着小程序商城的热度不减,更多的电商大佬纷纷使用小程序,如今已建立起2万开发者、1.2亿用户日活的小程序生态。微信对小程序的大力支持,也让无数的开发者和商户看到了微信小程序的无限发展潜力。但是,身边有很多朋友都会遇到一些问题,常见的就是在发布完的小程序后,自己的小程序在微信里搜不到的情况,这让很多企业商户摸不到头脑,那么出现这种状况的原因是什么呢?一、需登录小程序平台      在大家遇到小程序发布后搜索不到的情况时,首先需要登录自己的小程序平台,由于小程序审核通过后,还需要登录微信小程序平台“点击发布”这一项,在发布后的两小时内才可以搜索到自己的小程序,可以首先尝试一下此方法。二、小程序关键词排名规则      当你在微信中搜索小程序后,还是没有发现自己的小程序。很有可能是在小程序商城中小程序的关键词排名因素导致的。那么如何让自己的小程序关键词排名靠前呢?小编就和大家介绍一下小程序关键词的排名规则:1、小程序上线时间越早,排名就会越靠前。2、微信小程序用户使用的数量越多,排名就会越靠前。3、完全匹配出现关键词次数越多,排名就会越靠前。4、小程序的名称作为核心关键词语,排名就会越靠前。5、小程序中的关键词出现1次,并且整体标题的字数越短的话,排名就会越靠前。当大家遇到自己的小程序发布后在微信中搜索不到的情况时,可以通过以上提到的方法进行调整。随着微信对微信小程序商城的大力优化和扶持,越来越多的优势被大众所熟知,加之微信小程序正处于红利期,因此微信小程序的爆红也就不无道理了。
07-11
2017
基于Maven+SSM整合shiro+Redis实现后台管理项目
本项目由卖咸鱼叔叔开发完成,欢迎大神指点,慎重抄袭!参考了sojson提供的demo,和官方文档介绍。完整实现了用户、角色、权限CRUD及分页,还有shiro的登录认证+授权访问控制。项目架构:Maven + SpringMVC + Spring + Mybatis + Shiro + Redis数据库:MySql前端框架:H-ui 首先创建Maven项目1.pom.xml 加入依赖包<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>sys</groupId>  <artifactId>sys</artifactId>  <packaging>war</packaging>  <version>0.0.1-SNAPSHOT</version>  <name>sys Maven Webapp</name>  <url>http://maven.apache.org</url>        <dependencies>            <!-- spring依赖管理 -->            <!-- spring-context 是使用spring的最基本的环境支持依赖,会传递依赖core、beans、expression、aop等基本组件,以及commons-logging、aopalliance -->            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring-context</artifactId>                <version>4.3.2.RELEASE</version>            </dependency>                        <!-- spring-context-support 提供了对其他第三方库的内置支持,如quartz等 -->            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring-context-support</artifactId>                <version>4.3.2.RELEASE</version>            </dependency>                        <!-- spring-orm 是spring处理对象关系映射的组件,传递依赖了jdbc、tx等数据库操作有关的组件 -->            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring-orm</artifactId>                <version>4.3.2.RELEASE</version>            </dependency>                        <!-- spring-webmvc 是spring处理前端mvc表现层的组件,也即是springMVC,传递依赖了web等web操作有关的组件 -->            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring-webmvc</artifactId>                <version>4.3.2.RELEASE</version>            </dependency>                        <!-- spring-aspects 增加了spring对面向切面编程的支持,传递依赖了aspectjweaver -->            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring-aspects</artifactId>                <version>4.3.2.RELEASE</version>            </dependency>                                    <!-- json解析, springMVC 需要用到 -->            <dependency>                <groupId>com.fasterxml.jackson.core</groupId>                <artifactId>jackson-databind</artifactId>                <version>2.6.0</version>            </dependency>                        <!-- mybatis依赖管理 -->            <!-- mybatis依赖 -->            <dependency>                <groupId>org.mybatis</groupId>                <artifactId>mybatis</artifactId>                <version>3.3.0</version>            </dependency>                        <!-- mybatis和spring整合 -->            <dependency>                <groupId>org.mybatis</groupId>                <artifactId>mybatis-spring</artifactId>                <version>1.2.3</version>            </dependency>                        <!-- mybatis 分页插件 -->            <dependency>                <groupId>com.github.pagehelper</groupId>                <artifactId>pagehelper</artifactId>                <version>4.1.6</version>            </dependency>                        <!-- mysql驱动包依赖 -->            <dependency>                <groupId>mysql</groupId>                <artifactId>mysql-connector-java</artifactId>                <version>5.1.37</version>            </dependency>                        <!-- c3p0依赖 -->            <dependency>                <groupId>com.mchange</groupId>                <artifactId>c3p0</artifactId>                <version>0.9.5</version>            </dependency>                        <!-- redis java客户端jar包 -->            <dependency>                <groupId>redis.clients</groupId>                <artifactId>jedis</artifactId>                <version>2.9.0</version>            </dependency>                        <!-- 文件上传 -->            <dependency>                <groupId>commons-fileupload</groupId>                <artifactId>commons-fileupload</artifactId>                <version>1.3.1</version>            </dependency>                        <dependency>                <groupId>commons-io</groupId>                <artifactId>commons-io</artifactId>                <version>2.5</version>            </dependency>                        <dependency>                <groupId>org.apache.commons</groupId>                <artifactId>commons-email</artifactId>                <version>1.4</version>            </dependency>                        <dependency>                <groupId>org.apache.logging.log4j</groupId>                <artifactId>log4j-core</artifactId>                <version>2.7</version>            </dependency>                        <dependency>                <groupId>org.apache.httpcomponents</groupId>                <artifactId>httpclient</artifactId>                <version>4.5.2</version>            </dependency>                        <dependency>                <groupId>org.apache.httpcomponents</groupId>                <artifactId>httpcore</artifactId>                <version>4.4.4</version>            </dependency>                                    <!-- junit -->            <dependency>                <groupId>junit</groupId>                <artifactId>junit</artifactId>                <version>4.11</version>            </dependency>                        <!-- servlet依赖 -->            <dependency>                <groupId>javax.servlet</groupId>                <artifactId>javax.servlet-api</artifactId>                <version>3.1.0</version>                <scope>provided</scope>            </dependency>            <!-- jsp依赖 -->            <dependency>                <groupId>javax.servlet.jsp</groupId>                <artifactId>jsp-api</artifactId>                <version>2.2</version>                <scope>provided</scope>            </dependency>            <!-- jstl依赖 -->            <dependency>                <groupId>org.glassfish.web</groupId>                <artifactId>jstl-impl</artifactId>                <version>1.2</version>                <exclusions>                    <exclusion>                        <groupId>javax.servlet</groupId>                        <artifactId>servlet-api</artifactId>                    </exclusion>                    <exclusion>                        <groupId>javax.servlet.jsp</groupId>                        <artifactId>jsp-api</artifactId>                    </exclusion>                </exclusions>            </dependency>                                <dependency>            <groupId>net.sf.json-lib</groupId>            <artifactId>json-lib</artifactId>            <version>2.4</version>            <classifier>jdk15</classifier>        </dependency>        <dependency>            <groupId>commons-httpclient</groupId>            <artifactId>commons-httpclient</artifactId>            <version>3.1</version>        </dependency>                      <!-- shiro依赖包 -->        <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-core</artifactId>              <version>1.2.3</version>          </dependency>          <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-spring</artifactId>              <version>1.2.3</version>          </dependency>          <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-cas</artifactId>              <version>1.2.3</version>              <exclusions>                  <exclusion>                      <groupId>commons-logging</groupId>                      <artifactId>commons-logging</artifactId>                  </exclusion>              </exclusions>          </dependency>          <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-web</artifactId>              <version>1.2.3</version>          </dependency>          <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-ehcache</artifactId>              <version>1.2.3</version>          </dependency>          <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-quartz</artifactId>              <version>1.2.3</version>          </dependency>        <!-- shiro end -->                                    </dependencies>         <build>        <finalName>sys</finalName>        <plugins>            <!-- 指定JDK编译版本 -->            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.1</version>                  <configuration>                    <source>1.8</source>                  <target>1.8</target>                </configuration>            </plugin>        </plugins>    </build></project>2.SSM框架配置beans.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"    xsi:schemaLocation="http://www.springframework.org/schema/beans                        http://www.springframework.org/schema/beans/spring-beans.xsd                          http://www.springframework.org/schema/mvc                        http://www.springframework.org/schema/mvc/spring-mvc.xsd                        http://www.springframework.org/schema/context                        http://www.springframework.org/schema/context/spring-context.xsd                        http://www.springframework.org/schema/aop                        http://www.springframework.org/schema/aop/spring-aop.xsd                        http://www.springframework.org/schema/tx                        http://www.springframework.org/schema/tx/spring-tx.xsd">        <!-- 数据库连接池 -->    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">        <property name="driverClass" value="com.mysql.jdbc.Driver"/>          <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/sys_test?characterEncoding=UTF8&amp;allowMultiQueries=true"/>        <property name="user" value="root"/>          <property name="password" value="root"/>          <property name="maxPoolSize" value="100"/>          <property name="minPoolSize" value="10"/>          <property name="maxIdleTime" value="60"/>      </bean>        <!-- mybatis 的 sqlSessionFactory -->    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="dataSource"/>        <property name="configLocation" value="classpath:mybatis-config.xml"></property>    </bean>        <!-- mybatis mapper接口自动扫描、自动代理 -->    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">       <property name="basePackage" value="com.sys.mapper" />    </bean>        <!-- 事务管理器 -->    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" />    </bean>    <!-- 事务传播行为 -->    <tx:advice id="txAdvice" transaction-manager="txManager">        <tx:attributes>            <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>            <tx:method name="page*" propagation="SUPPORTS" read-only="true"/>            <tx:method name="is*" propagation="SUPPORTS" read-only="true"/>            <tx:method name="*" propagation="REQUIRED" read-only="false"/>        </tx:attributes>    </tx:advice>    <!-- 织入事务增强功能 -->    <aop:config>        <aop:pointcut id="txPointcut" expression="execution(* com.sys.service..*.*(..))" />        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />    </aop:config>     <!-- 配置扫描spring注解(@Component、@Controller、@Service、@Repository)时扫描的包,同时也开启了spring注解支持 -->     <!-- 这个地方只需要扫描service包即可,因为controller包由springMVC配置扫描,mapper包由上面的mybatis配置扫描 -->    <context:component-scan base-package="com.sys.service"></context:component-scan>    <!-- 开启spring aop 注解支持,要想aop真正生效,还需要把切面类配置成bean -->    <aop:aspectj-autoproxy/>         </beans>dispatcher-servlet.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"    xsi:schemaLocation="http://www.springframework.org/schema/beans                        http://www.springframework.org/schema/beans/spring-beans.xsd                          http://www.springframework.org/schema/mvc                        http://www.springframework.org/schema/mvc/spring-mvc.xsd                        http://www.springframework.org/schema/context                        http://www.springframework.org/schema/context/spring-context.xsd                        http://www.springframework.org/schema/aop                        http://www.springframework.org/schema/aop/spring-aop.xsd                        http://www.springframework.org/schema/tx                        http://www.springframework.org/schema/tx/spring-tx.xsd">                            <!-- 配置扫描spring注解时扫描的包,同时也开启了spring注解支持 -->    <context:component-scan base-package="com.sys" />    <!-- 开启springMVC相关注解支持 -->    <mvc:annotation-driven />        <!-- 开启spring aop 注解支持 -->    <aop:aspectj-autoproxy/>        <!-- 约定大于配置:约定视图页面的全路径 = prefix + viewName + suffix -->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="prefix" value="/WEB-INF/jsp/"></property>        <property name="suffix" value=".jsp"></property>    </bean>    <!-- 文件上传解析器 -->    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">        <property name="maxUploadSize" value="104857600" />        <property name="defaultEncoding" value="UTF-8" />        <property name="maxInMemorySize" value="40960" />    </bean>        <!-- 资源映射 -->    <mvc:resources location="/css/" mapping="/css/**" />    <mvc:resources location="/js/" mapping="/js/**" />    <mvc:resources location="/images/" mapping="/images/**" />    <mvc:resources location="/skin/" mapping="/skin/**" />    <mvc:resources location="/lib/" mapping="/lib/**" /> </beans>mybatis-config.xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <settings>        <!-- 使用log4j2作为日志实现 -->        <setting name="logImpl" value="LOG4J2"/>    </settings>    <typeAliases>        <!-- 为指定包下的pojo类自动起别名 -->        <package name="com.sys.pojo"/>    </typeAliases>        <mappers>        <!-- 自动加载指定包下的映射配置文件 -->        <package name="com.sys.mapper"/>    </mappers></configuration>Log4j2.xml <?xml version="1.0" encoding="UTF-8"?>  <!DOCTYPE xml><Configuration status="OFF">    <Appenders>        <Console name="CONSOLE" target="SYSTEM_OUT">            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{0} - %msg%n" />        </Console>        <RollingFile name="ROLLING" fileName="/logs/ups-manager/log.log"             filePattern="/logs/log_%d{yyyy-MM-dd}_%i.log">            <PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/>            <Policies>                <TimeBasedTriggeringPolicy modulate="true" interval="1"/>                <SizeBasedTriggeringPolicy size="1024 KB"/>            </Policies>            <DefaultRolloverStrategy max="100"/>        </RollingFile>    </Appenders>        <Loggers>        <Root level="debug">            <AppenderRef ref="CONSOLE" />            <AppenderRef ref="ROLLING"/>        </Root>                <!-- 控制某些包下的类的日志级别 -->        <Logger name="org.mybatis.spring" level="error">            <AppenderRef ref="CONSOLE"/>        </Logger>    </Loggers></Configuration>web.xml<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">    <!-- 初始化spring容器 -->    <listener>        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>        <!-- 设置post请求编码和响应编码 -->    <filter>        <filter-name>characterEncodingFilter</filter-name>        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>            <init-param>                <param-name>encoding</param-name>                <param-value>UTF-8</param-value>            </init-param>        <init-param>            <!-- 为true时也对响应进行编码 -->            <param-name>forceEncoding</param-name>            <param-value>true</param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>characterEncodingFilter</filter-name>        <!-- 设置为/*时才会拦截所有请求,和servlet有点区别,servlet设置为/*只拦截所有的一级请求,如/xx.do,而不拦截/xx/xx.do;servlet设置为/时才会拦截所有请求 -->        <url-pattern>/*</url-pattern>    </filter-mapping>    <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>            classpath:spring-shiro.xml,            classpath:beans.xml,            classpath:dispatcher-servlet.xml        </param-value>    </context-param>          <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->    <filter>        <filter-name>shiroFilter</filter-name>        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>        <init-param>            <param-name>targetFilterLifecycle</param-name>            <param-value>true</param-value>        </init-param>    </filter>          <filter-mapping>        <filter-name>shiroFilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>        <!-- 初始化springMVC容器 -->    <servlet>        <servlet-name>dispatcher</servlet-name>        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>        <init-param>            <param-name>contextConfigLocation</param-name>            <param-value>classpath:dispatcher-servlet.xml</param-value>        </init-param>        <load-on-startup>1</load-on-startup>    </servlet>      <servlet-mapping>        <servlet-name>dispatcher</servlet-name>        <url-pattern>/</url-pattern>    </servlet-mapping>        </web-app>3.实现用户、角色、权限页面操作功能,这里就不贴代码了4.接下来就是shiro,登录认证和授权只需要继承AuthorizingRealm,其继承了 AuthenticatingRealm(即身份验证),而且也间接继承了 CachingRealm(带有缓存实现)。身份认证重写doGetAuthenticationInfo方法,授权重写doGetAuthorizationInfo方法。Shiro 默认提供的 Realm 身份认证流程 流程如下:首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。 代码实现:/** * */package com.sys.shiro;import javax.annotation.Resource;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AccountException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.DisabledAccountException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.subject.SimplePrincipalCollection;import org.apache.shiro.util.ByteSource;import com.sys.pojo.AdminUser;import com.sys.service.AdminUserService;/**  * @ClassName: MyRealm  * @Description: shiro 认证 + 授权   重写 */public class MyRealm extends AuthorizingRealm {    @Resource    AdminUserService adminUserService;            /* (non-Javadoc)     * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)     */    /**     * 授权Realm     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        String account = (String)principals.getPrimaryPrincipal();        AdminUser pojo = new AdminUser();        pojo.setAccount(account);        Long userId = adminUserService.selectOne(pojo).getId();        SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();        /**根据用户ID查询角色(role),放入到Authorization里.*/        info.setRoles(adminUserService.findRoleByUserId(userId));        /**根据用户ID查询权限(permission),放入到Authorization里.*/        info.setStringPermissions(adminUserService.findPermissionByUserId(userId));        return info;    }    /* (non-Javadoc)     * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)     */    /**     * 登录认证Realm     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {        String username = (String)token.getPrincipal();        String password = new String((char[])token.getCredentials());        AdminUser user = adminUserService.login(username, password);        if(null==user){            throw new AccountException("帐号或密码不正确!");        }        if(user.getIsDisabled()){            throw new DisabledAccountException("帐号已经禁止登录!");        }        //**密码加盐**交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配        return new SimpleAuthenticationInfo(user.getAccount(),user.getPassword(),ByteSource.Util.bytes("3.14159"), getName());    }        /**     * 清空当前用户权限信息     */    public  void clearCachedAuthorizationInfo() {        PrincipalCollection principalCollection = SecurityUtils.getSubject().getPrincipals();        SimplePrincipalCollection principals = new SimplePrincipalCollection(                principalCollection, getName());        super.clearCachedAuthorizationInfo(principals);    }    /**     * 指定principalCollection 清除     */    public void clearCachedAuthorizationInfo(PrincipalCollection principalCollection) {        SimplePrincipalCollection principals = new SimplePrincipalCollection(                principalCollection, getName());        super.clearCachedAuthorizationInfo(principals);    }        }shiro的配置:spring-shiro.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <!--shiro 核心安全接口  -->        <property name="securityManager" ref="securityManager"></property>        <!--登录时的连接  -->        <property name="loginUrl" value="/login"></property>              <!--未授权时跳转的连接  -->        <property name="unauthorizedUrl" value="/unauthorized.jsp"></property>           <!-- 其他过滤器 -->           <property name="filters">               <map>                   <!-- <entry key="rememberMe" value-ref="RememberMeFilter"></entry> -->                   <entry key="kickout" value-ref="KickoutSessionControlFilter"/>               </map>           </property>                      <!-- 读取初始自定义权限内容-->        <!-- 如果使用authc验证,需重写实现rememberMe的过滤器,或配置formAuthenticationFilter的Bean -->        <property name="filterChainDefinitions">            <value>                /js/**=anon                /css/**=anon                /images/**=anon                /skin/**=anon                   /lib/**=anon                   /nodel/**=anon                   /WEB-INF/jsp/**=anon                   /adminUserLogin/**=anon                                                             /**/submitLogin.do=anon                /**=user,kickout            </value>        </property>    </bean>                    <!-- Shiro生命周期处理器-->    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />        <!-- 安全管理器 -->    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <property name="realm" ref="MyRealm"/>        <property name="rememberMeManager" ref="rememberMeManager"/>    </bean>        <bean id="MyRealm" class="com.sys.shiro.MyRealm" >        <property name="cachingEnabled" value="false"/>    </bean>        <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>        <property name="arguments" ref="securityManager"/>    </bean>        <!-- sessionIdCookie:maxAge=-1表示浏览器关闭时失效此Cookie -->    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">          <constructor-arg value="rememberMe"/>          <property name="httpOnly" value="true"/>          <property name="maxAge" value="-1"/>      </bean>            <!-- 用户信息记住我功能的相关配置 -->    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">        <constructor-arg value="rememberMe"/>        <property name="httpOnly" value="true"/>        <!-- 配置存储rememberMe Cookie的domain为 一级域名        这里如果配置需要和Session回话一致更好。-->        <property name="maxAge" value="604800"/><!-- 记住我==保留Cookie有效7天 -->    </bean>        <!-- rememberMe管理器 -->    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">        <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)-->        <property name="cipherKey"                  value="#{T(org.apache.shiro.codec.Base64).decode('3AvVhmFLUs0KTA3Kprsdag==')}"/>        <property name="cookie" ref="rememberMeCookie"/>    </bean>        <!-- 记住我功能设置session的Filter -->    <bean id="RememberMeFilter" class="com.sys.shiro.RememberMeFilter" />        <!-- rememberMeParam请求参数是 boolean 类型,true 表示 rememberMe -->    <!-- shiro规定记住我功能最多得user级别的,不能到authc级别.所以如果使用authc,需打开此配置或重写实现rememberMe的过滤器 -->    <!-- <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">        <property name="rememberMeParam" value="rememberMe"/>    </bean> -->            <bean id="KickoutSessionControlFilter" class="com.sys.shiro.KickoutSessionControlFilter">    </bean>                  </beans>5.登录即密码失败多次后锁定/** * */package com.sys.controller;import java.util.LinkedHashMap;import java.util.Map;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AccountException;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.DisabledAccountException;import org.apache.shiro.authc.ExcessiveAttemptsException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import com.sys.pojo.AdminUser;import com.sys.service.AdminUserService;import com.sys.common.JedisUtils;import com.sys.shiro.ShiroUtils;/**  * @ClassName: LoginController  * @Description: 登录*/@Controllerpublic class LoginController{    protected final static Logger logger = LogManager.getLogger(LoginController.class);    protected Map<String, Object> resultMap = new LinkedHashMap<String, Object>();        @Resource    AdminUserService adminUserService;        /**    * @Description: 登录认证    * @param um 登录账号    * @param pw 登录密码    * @param rememberMe 记住我    * @param request    * @return    * @throws      * @author lao    * @Date 2018年1月15日下午12:24:19    * @version 1.00     */    @RequestMapping(value="/submitLogin.do",method=RequestMethod.POST)    @ResponseBody    public Map<String,Object> submitLogin(String um,String pw,boolean rememberMe,HttpServletRequest request){                Subject subject = SecurityUtils.getSubject();        UsernamePasswordToken token = new UsernamePasswordToken(um,ShiroUtils.getStrByMD5(pw));                            try{                      token.setRememberMe(rememberMe);            subject.login(token);            JedisUtils.del(um);            logger.info("------------------身份认证成功-------------------");            resultMap.put("status", 200);            resultMap.put("message", "登录成功!");        } catch (DisabledAccountException dax) {              logger.info("用户名为:" + um + " 用户已经被禁用!");            resultMap.put("status", 500);            resultMap.put("message", "帐号已被禁用!");        } catch (ExcessiveAttemptsException eae) {              logger.info("用户名为:" + um + " 用户登录次数过多,有暴力破解的嫌疑!");            resultMap.put("status", 500);            resultMap.put("message", "登录次数过多!");        } catch (AccountException ae) {              logger.info("用户名为:" + token.getPrincipal() + " 帐号或密码错误!");            String excessiveInfo = ExcessiveAttemptsInfo(um);            if(null!=excessiveInfo){                resultMap.put("status", 500);                resultMap.p
06-17
2017
有关Servlet和JSP的梳理
大二第一学期的时候有学JSP的课,但是因为在开学之前做过JSP的小项目,所以一个学期的课也没听,直到期末考试成绩出来了,才回想JSP的内容还有多少记得,没想到模模糊糊也记不起多少,赶紧回头学回来。接下来是关于Servlet和JSP的梳理。-------------------------------------------------------------------------------------------------------------------------------------------------  Servlet是一个Java程序,一个Servlet应用有一个或多个Servlet程序,而且JSP页面也会被转换和编译成Servlet程序。  Servlet应用无法独立运行,必须运行在Servlet容器中。Servlet容器将用户的请求传递给Servlet应用,并将结果返回给用户。由于大部分Servlet应用都包含多个JSP页面,因此更准确地说是“Servlet/JSP应用”。  其中,Servlet API是开发Servlet的主要技术。而Servlet API有以下4个Java包:Java包包含的内容javax.servlet定义Servlet和Servlet容器之间契约的类和接口javax.servlet.http定义HTTP Servlet和Servlet容器之间契约的类和接口javax.servlet.annotation标注Servlet、Filter、Listener的标注。它还被标注原件定义元数据javax.servlet.descriptor包含提供程序化登陆web应用程序的配置信息的类型。  Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口,而Servlet接口定义了Servlet与Servlet容器之间的契约。这个契约归结起来就是,Servlet容器将Servlet类载入内存,并在Servlet实例上调用具体的方法。当用户的请求使得Servlet容器调用Servlet的Service方法,会传入一个ServletRequest实例和一个ServletResponse实例,其中,ServletRequest中封装了当前的HTTP请求,而ServletResponse表示当前用户的HTTP响应。对于每一个应用程序,Servlet容器还会创建一个ServletContext实例,这个对象中封装了上下文(应用程序)的环境详情。每个上下文只有一个ServletContext,而且每个Servlet实例都有一个配置的ServletConfig。  Servlet的生命周期方法:  Servlet容器的生命周期方法作用init该方法在Servlet第一次被请求的时候,Servlet就会调用这个方法,而后不再被调用,所以可以用这个方法进行初始化工作。调用这个方法时,Servlet容器会传入一个ServletConfig。Service每当请求Servlet时,Servlet容器就会调用这个方法。第一次请求Servlet时,Servlet容器调用init方法和Service方法。后续的请求将只调用Service方法。destroy当要销毁Servlet时,Servlet容器就会调用这个方法。一般会在这个方法中编写清除代码。  在介绍一个Servlet中另外两个非生命周期的方法:Servlet容器的非生命周期方法作用getServletInfo这个方法会返回Servlet的描述getServletConfig这个方法会返回由Servlet容器传给init方法的ServletConfig。但是为了让getServletConfig返回一个非null值,必须将传给init方法的ServletConfig赋给一个类级变量。-------------------------------------------------------------------------------------------------------------------------------------------------   接下来是Servlet的各类接口:  ServletRequest 接口说明ServletRequest对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。  常用的方法有:    方法说明public int getContentLength()返回请求主体的字节数。public java.lang.String getContentType()返回请求主体的MIME类型。public java.lang.String getParameter(java.lang.String name)返回指定请求参数的值public java.lang.String getProtocol()返回这个HTTP请求的协议名称和版本  ServletResponse接口说明ServletResponse该接口表示一个Servlet响应。在调用Servlet的Service方法前,Servlet容器首先创建一个ServletResponse,并将它作为第二个参数传给Service方法。ServletResponse隐藏了向浏览器发送响应的复杂过程。  常用的方法: 方法说明getWriter()返回了一个可以向客户端发送文本的java.io.PrintWriter。默认情况下,PrintWriter对象使用ISO-8859-1编码。setContentType(“type”)设置响应的内容类型,并将”text/html”作为一个参数传入。如果没有设置相应内容类型,有些浏览器就会将HTML标签显示为普通文本。  ServletConfig  接口说明ServletConfig用于存储关于Servlet的配置信息。当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init()方法传入一个ServletConfig。ServletConfig封装可以通过@WebServlet或描述符传给Servlet的配置信息。   常用的方法: 方法说明java.lang.String getInitParameter(java,lang.String name)为了从Servlet内部获取到初始参数的值,要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。java.util.Enumration<java.lang.String> getInitParameterNames()返回所有初始参数名称的一个Enumeration。String contactName = servletConfig.getInitParameter(“contactName”)获取contactName参数值  ServletContext接口说明ServletContext每个Web应用程序只有一个上下文,所以ServletContext可以存储这个上下文,并且ServletContext还可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象,而且是用ServletContext内部的Map保存。  常用的方法: 方法说明getServletContext().getInitParameter(String name)获取在项目下的web.xml中设置context的初始化参数this.getServletContext().log(“测试”)在web.xml文件中,使用logger元素来设置日志文件getAttribute(String name)/get AttributeNames()获取ServletContext中的属性setAttribute(String name, Object object)设置ServletContext中的属性removeAttribute(String name)移除ServletContext中的属性  GenericServlet接口说明GenericServletGenericServlet实现了Servlet和ServletConfig接口。将init方法中的ServletConfig赋给一个类级变量,以便可以通过getServletConfig获取,为Servlet接口中的所有方法提供默认的实现,而且提供包括ServletConfig中的方法。  Http Servlets    接口说明HttpServletHttpServlet类覆盖了javax.servlet.GenericServlet类。使用HttpServlet时,还要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。而HttpServlet与GenericServlet的差别在于,HttpServlet覆盖的是doGet或者doPost方法,而不是Service方法,而且使用的是HttpServletRequest和HttpServletResponse,而不是ServletRequest和ServletResponse。HttpServletRequest表示HTTP环境中的Servlet请求HttpServletResponse表示HTTP环境中的Servlet响应  各个接口常用的方法如下:  接口方法说明 HttpServletRequestjava.lang.String getContextPath()返回表示请求上下文的请求URI部分。 HttpServletRequestCookie[] getCookies()返回一个Cookie对象的数组。 HttpServletRequestjava.lang.String getHeader(java.lang.String name)返回指定HTTP标题的值。 HttpServletRequestjava.lang.String getMethod()返回生成这个请求的HTTP方法名称 HttpServletRequestjava.lang.String getQueryString()返回请求URL中的查询字符串。 HttpServletRequestHttpSession getSession()返回与这个请求相关的会话对象。如果没有,将创建一个新的会话对象。 HttpServletRequestHttpSession getSession(Boolean create)返回与这个请求相关的绘画对象,如果有,并且create参数为True,将创建一个新的会话对象。 HttpServletResponsevoid addCookie(Cookie cookie)给这个响应对象添加一个cookie。 HttpServletResponsevoid addHeader(java.lang.String name, java.lang.String value)给这个响应对象添加一个header。 HttpServletResponsevoid sendRedirect(java.lang.String location)发送一条响应码,将浏览器跳转到指定的位置。-------------------------------------------------------------------------------------------------------------------------------------------------  当用户提交HTML表单时,在表单元素中输入的值就会被当作请求参数发送到服务器。HTML输入域(文本域、隐藏域或者密码域)或者文本区的值,会被当作字符串发送到服务器。空的输入域或者文本区会发送空的字符串。  包含多个值的select元素发出一个字符串数组,可以通过ServletRequest.getParameterValues进行处理。  核查过的复选框会发送字符串"on"到服务器,未经核查的复选框则不向服务器发送任何内容,ServletRequest.getParameter(fieldName)返回null。  单选框将被选中按钮的值发送到服务器。如果没有选择任何按钮,将没有任何内容被发送到服务器,并且ServletRequest.getParameter(fieldName)返会null。  如果一个表单中包含多个输入同名的元素,那么所有值都会被提交,并且必须利用ServletRequest.getParameterValues来获取它们。ServletRequest.getParameter将只返回最后一个值。