不同权限用户登陆后现实的页面不同 怎么用 h5+jsh5实现强制关注公众号

无论QQ还是微信,处处都体现着连接&人和人&的目的。而微信企业号的出现、微信红包的火热、JS SDK的开放、微信硬件开放平台的推出,更是将早已是超级APP的微信&连接一切&的野心暴露无疑。智能手机早已广泛普及,微信超级APP的地位也日益凸显。在2014年的微信营销中,各路营销高手使劲浑身解数,让我们见识了营销高手们各显神通的传播实力。而这其中,使用HTML5(以下简称H5)制作炫酷页面的营销方式更是刷爆了我们的眼球。 H5是超文本标记语言(HTML)的第五次重大修改,基于HTML5开发的网页APP拥有更短的启动时间,更快的联网速度。通俗的讲,使用H5制作的微页面,在微信的宣传中,重点突出、目标明确、交互更具吸引力。那要制作H5页面是不是只能去学代码呢?当然不是! 自从H5爆红后,制作H5页面的工具层出不穷,已经多到叫人目不暇接了,不信?往下看:epub360、vxplo互动大师、码卡MAKA、易企秀、兔展、初页、易传单、未来应用、品趣、点点客海报、秀制作、微杂志(有赞商城,原口袋通)、云来(LiveApp)、最酷轻应用、COOLAPP、我傲、、居高互动刊、调用等等等如果只能做请帖或邀请函也算的话,还有:快邀约,微喜帖、维斗喜帖、聚喜===如果国外的也算的话,听(英)说(语)还(不)有(好):Wix、Google Web Designer、Weebly、Ceilfire、Jimdo、Mixeek反正已经多的让DEMO8小伙伴们眼花缭乱了,当然肯定还有没有统计到的。一 分类在详细介绍这些H5工具之前,我们先把它们做个简单的分类,按照这些H5工具的自主定制空间及使用方式等,将它们分为以下三类:&完全自主定制: epub360、vxplo互动大师&模板一样快捷:码卡MAKA、易企秀、兔展、易传单、未来应用、品趣、点点客海报、秀制作、微杂志(有赞商城,原口袋通)、云来(LiveApp)、最酷轻应用、COOLAPP、木疙瘩、居高互动刊、调用等等等(其实模板更好理解一些,但是遭到了众多朋友反对,强烈声明不是模板,那就改成&像模板一样快捷&吧)&APP:vxplo互动大师、初页、聚喜、我傲、易企秀等(vxplo以网页端为主,用户主要面向企业级,推出的APP主要是为了满足相对非专业的用户的需求)不同类型H5工具的对比:&自主定制类:优势:完全自主定制、可操作性强劣势:功能较多,学习时间成本较大&非自主定制类:优势:操作简单、随学随用劣势:只能选择使用,不能定制功能和交互效果。一句话来描述&自主定制类&和&非自主定制类&H5工具的区别:一言以蔽之:就是Photoshop和的区别至于孰优孰劣,那就看使用者的需求,仁者见仁智者见智了!二 收费模式在给这些H5工具做了简单分类之后,我们来谈谈最现实的问题:钱&&收费模式的问题。据不完全统计(本次抽样统计的样本为:epub360、vxplo互动大师、maka、兔展、易企秀等),H5工具收费模式主要有:1 免费(含广告)版 大多数的H5工具,都采用增值付费的模式。即提供含广告的免费版,如果需要去除广告,则需要支付相关费用。广告形式主要有两种:一种是在加载页显示对应LOGO和&由XX提供技术支持&字样;另一种是在最后一页显示&免费创建这样的展示&&点击制作我的XX&等2 付费版(价格从单两块钱一次到每年59999不等) 免费的版本大抵相同,付费的版本各有各的理(jie)由(kou):a 按时间和次数,导出一次的价格、多次&团购&价格,以及月付费价格、年付费价格等价格最低的应该是秀制作无疑,因为看到下面的数字你就明白了: 价格最高的应该是epub360,人民币59999元每年,不过功能也是最全面的,期待更高的价格: b 作品数量限制,站内存储空间、站外数据流量选择不同的价格套餐,会有相应的作品数量限制,也有的H5工具限制站内存储空间或是站外的数据流量。如上图,epub360免费版最多可创建10个H5页面,相应存储空间只有2G;而站外数据流量,是像vxplo这样,通过获取作品的js、div、html代码,嵌入自己的网站,在分享的时候用户看到的事你自己的域名,这样就会产生站外数据流量。c 数据监测功能:PV、UV、访问地址、手机型号通过划分不同的付费标准,提供用户数据监测的权限,包括用户访问的PV、UV、访问来源、使用的手机型号等等d 访问加速、作品优化等通过技术手段对作品进行优化,加快作品打开速度等,当然了,会有加速程度的划分和作品优化次数的限制。e 客服支持每一种H5都有技术支持、帮助的方式,如通过论坛、邮件、电话、QQ群等方式进行咨询,而高级VIP用户,更是可以获得专属客服顾问服务f HTML文件导出、专用域名可自主定制的epub360,可以通过导出HTML文件发布到自己的网站上,也可以通过绑定到专用的域名来进行发布;而对于同样类型的vxplo,可通过代码嵌套的形式达到显示用户自己域名的目的。g 其他增值功能微信的规则不断变化,各个H5工具也是紧随其后。而高级VIP用户,肯定会在第一时间尝到甜头。如微信拍照功能、摇一摇、点赞等等三 重要元素1 背景图 炫酷的画面,离不开背景的衬托,能否快速更换背景图,相信是考验一个H5页面能否快速完成的准则之一(上面这图眼熟吧)2 文本 微信交互H5页面更重交互,重视觉效果,在酷炫的背景衬托之下,突出重点的文字往往是点睛之笔3 音乐
炫酷的背景下,配以提纲挈领式的文字,如果能够再来一段能够引起共鸣的音乐,那是何等的应景,此时,我百度了下&H5页面背景音乐&,试听之下,心潮澎湃!激情四射!4 图片 背景之外,重点图片之间的交互、与文字的配合正是H5页面能够调动用户感官的重要方式!光速的定义是光在1秒内行驶距离的分之一,所以光速比声速快,比打字速度更快。那为什么不用图片呢?5 视频如果炫酷的背景、精炼的文字、应景的音乐,还不能够让你感到震撼的话,那就来段视频吧!一目了然!6 按钮(点击跳转链接)H5页面在微信展示的优势是交互效果好,观赏性强,但是归根结底,还是要回到营销的目的上来。或用于宣传,需要链接到更为详尽的介绍页面;或用户收集信息,需要链接到指定的信息收集页面。如此一来,是否具有点击跳转功能就成为判断一个H5工具是否可供选择的硬性标准之一。当然,也有个别H5工具对&点击按钮&这样的功能,用付费与免费做了区分,在对比了众多工具之后,我认为这是很没有必要的。当然了,如果它的用户对H5工具所知甚少,又疏于使用搜索引擎查找的话,这样的做法也不失为一个不错的盈利点。7 输入框在微信H5页面中,除宣传类外,大部分都是以收集信息为目的的。除了使用表单、金数据、问卷星等第三方表单收集工具外,各个H5工具内置的输入框功能也不失为一个很好的选择。这样,在对应的后台,不仅可以看到访问信息(如已有查看权限),还可查看详细报名数据。8 其他微信规则处于动态平衡、不断变化中,各家H5工具也会随着相应变化。每一个新功能的出现,都足以成为一个亮点,迅速火爆朋友圈。如图片替换功能,用你自己的图片替换掉作品中名人的图片;摇一摇参加互动等等。四 常见交互效果对于定制类H5工具如vxplo互动大师、epub360,交互效果完全可定制,只有想不到、没有做不到!对于非定制类的H5工具,也都提供了足够多的可供选择的交互方式。 据不完全统计,主要交互效果有:1 飞入,从上下左右不同方向飞入页面2 淡出,透明度由弱变强,带用户进入画面3 旋转,2D旋转和3D旋转,增强观赏性4 大小,从小到大,从大到小,重点突出5 跳跃和抖动,跳跃、抖动的元素,活泼可爱6 擦除效果,用手擦一擦,见证惊奇的时刻7 指纹识别,就是长按功能,加上指纹识别的概念,瞬间高大上8 其他,加上&雨滴&&烟花&&闪烁&&粒子化&等特效,档次立马就不一样五 其他 任何一个效果的完善,都足以让用户充满敬意;任何一个细节的优化,都足以让用户感受到认真和品质;任何一个功能的改进,都足以让用户在使用与放弃之间做出选择;也许,选择使用一种H5工具,只是因为它更换图片比其它工具都要快;也许,选择使用一种H5工具,只是因为它复制案例比其它工具更轻松;也许,选择使用一种H5工具,只是因为它的编辑器布局更加容易记忆;你觉得呢?总而言之,工具毕竟是工具。页面做的再精美,交互做的再有吸引力,没有微信这样的超级平台,没有微信开放的态度,没有微信连接一切的野心,恐怕都很难如此迅速的传播开去! 所有的工具都会随着微信规则的改变而改变,但是我们看到的交互效果会越来越精美,越来越有吸引力;微信催生了一批H5工具,而这些H5工具的诞生和发展,一定会在基于微信的营销方式中书写浓墨重彩的一笔,难道这,还不够吗?体验H5工具们,戳
24小时报不停
支付宝悄然上线圈子社交功能 部分用户上传大尺度“写真”
俄罗斯已在研发杀人机器人, 6千米外即可射杀人类
科学家发明可弯曲的超级电池:充电几秒钟,通话一礼拜
苹果获得新专利:iPhone 8是否会变成翻盖手机?
网联平台拟于明年3月31日上线 央行或入股查看: 7217|回复: 28
实现一个js文件在几个不同的连续跳转页面上执行
zhangbobell
各位大牛,我想实现一个js文件在几个不同的连续跳转页面上执行,目前有两个思路:
1)利用chrome浏览器监听特定页面,然后在特定的页面执行js文件,此时把刚说的js文件分成好几个js文件执行就行了。就是不知道chrome插件有没有实现这个功能的?
2)有没有js文件能再不同的几个页面中一次执行的?
请教大家,求助,谢谢!!
narutovsop
不是很明白你的意思,不同页面执行不同脚本可以在manifest里或每个脚本里的include字段里进行设定
zhangbobell
narutovsop 发表于
不是很明白你的意思,不同页面执行不同脚本可以在manifest里或每个脚本里的include字段里进行设定
那怎么样在manifest里面写呢?使得特定的js在特定的页面才会被触发执行,从而实现页面连续跳转,然后就会顺序执行。
就是:页面1-----执行1.js
& && & 页面2-----执行2.js
& && & 页面3-----执行3.js
谢谢回复!
narutovsop
zhangbobell 发表于
那怎么样在manifest里面写呢?使得特定的js在特定的页面才会被触发执行,从而实现页面连续跳转,然后就会 ...
你可以下载ABP,然后看看里面的manifest文件,主要是在content_scripts字段里进行添加&content_scripts&: [ {
& && &&js&: [ &执行1.js& ],
& && &&matches&: [ &页面1& ]
& & }, {
& && &&js&: [ &执行2.js& ],
& && &&matches&: [ &页面2& ]
& & }, {
& && &&js&: [ &执行3.js& ],
& && &&matches&: [ &页面3& ]
& & } ], 复制代码
zhangbobell
narutovsop 发表于
你可以下载ABP,然后看看里面的manifest文件,主要是在content_scripts字段里进行添加
嗯,非常感谢,我下载了ABP,看了他的代码,知道怎么做的,但是现在还是没法达到我要的效果。
我定义了两个数组,username和password,想让他们自动在在登录页面从第一个执行到最后一个,但是想了想,如果用var username = new Array();
var password = new Array();
var flag = new Array();
username[0]=&user1&;
password[0]=&123456r&;
flag[0] =
username[1]=&user2&;
password[1]=&123&;
flag[1] =
for(var i = 0; i & username. i++)
{
& & & & if(!flag[i])
& & & & {
& & & & & & & & flag[i]=
& & & & & & & & login(username[i], password[i]);& & & &
& & & & }& & & &
}复制代码这样好像不行,因为一旦第一个用户名完成了操作之后,当再次跳到登录页面时,那个flag数组并没有更新,而是还是都是false状态,所以还会从第一个用户名开始执行的,我不知道怎么样才能顺利地连续执行这多个用户名的登录,我很困惑。谢谢版主narutovsop,不知道你有没有好的办法?
narutovsop
本帖最后由 narutovsop 于
01:02 编辑
zhangbobell 发表于
嗯,非常感谢,我下载了ABP,看了他的代码,知道怎么做的,但是现在还是没法达到我要的效果。
我定义了 ...
一个页面下应该是无法执行两次登录操作的,而且登录操作一般会刷新页面,因为会有跳转操作,所以脚本会重新执行,状态也就都重置为false了,如果是特定页面的话可以用localStorage或sessionStorage来存储数组里的数据,这样就不需要担心页面刷新情况了,例如如下,localStorage[]用来替换那个flag,你试试看var username = new Array();
var password = new Array();
var flag = new Array();
username[0]=&user1&;
password[0]=&123456r&;
if(!localStorage['0'])localStorage['0'] = &false&;
username[1]=&user2&;
password[1]=&123&;
if(!localStorage['1'])localStorage['1'] = &false&;
for(var i = 0; i & username. i++)
{var flag=JSON.parse(localStorage[i]);
        if(!flag)
        {
                localStorage[i]=
                login(username[i], password[i]);       
        }       
zhangbobell
narutovsop 发表于
一个页面下应该是无法执行两次登录操作的,而且登录操作一般会刷新页面,因为会有跳转操作,所以脚本会 ...
非常感谢你的回复,刚开始开发还望多指教,这种方法是可行的,现在出现了问题是:content_scripts里面的matches的网址在特定页面是工作的,但是遇到一些情况他不工作了,例如我碰到的http://h5./my/index.htm#!myTaobao这种网址,我怀疑是不是#号的原因,这种情况不知道有没有什么解决办法,我使用了模式匹配,甚至http://*/*都不行,我不知道是什么原因。
narutovsop
zhangbobell 发表于
非常感谢你的回复,刚开始开发还望多指教,这种方法是可行的,现在出现了问题是:content_scripts里面的m ...
没遇到过这种情况,有#号应该不会有影响,如图,只是一个简单的console.log功能,说明这种网址下是可以正常加载脚本的
QQ截图12.png (45.57 KB, 下载次数: 5)
11:44 上传
你可以刷新页面然后看看审查元素 - sources - Content scripts下是否加载这个脚本
另外,对于比较复杂或不容易匹配的网址可以用include_globs来,你可以看看
zhangbobell
narutovsop 发表于
没遇到过这种情况,有#号应该不会有影响,如图,只是一个简单的console.log功能,说明这种网址下是可以正 ...
嗯,是我写的脚本有点问题,确实是加载了,谢谢你,再请教一个关于js的问题,比如这种网址http://h5./we/index.htm?#account//1,右上角的“关注”在源代码看是button,但是利用js捕捉时,并没有捕捉到。我的代码如下:function clickButton()
{
& & & & var numOfbutton=0;
& & & & if(document.getElementsByTagName(&button&) != null)
& & & & & & & & numOfbutton = document.getElementsByTagName(&button&).
& & & & alert(numOfbutton);
& & & & for(var i = 0;i&numOi++)
& & & & {
& & & & & & & & alert(document.getElementsByTagName(&button&)[i].innerHTML);
& && &&&if(document.getElementsByTagName(&button&)[i].innerHTML == &关注&)
& && && && &{
& && && && && & alert(&this is the shop page ,And prepare to click the focus button.&);
& && && && && & document.getElementsByTagName(&button&)[i].click();//点击&关注&
& && && && && && & & &
& && && && &}
& & & & }
}复制代码alert提示总共button的数目只有四个,捕捉到的是有,“发送”,“确定”,“取消”,“重试”,没有“关注”,我不知是什么原因。谢谢!
narutovsop
zhangbobell 发表于
嗯,是我写的脚本有点问题,确实是加载了,谢谢你,再请教一个关于js的问题,比如这种网址http://h5.m.ta ...
代码应该没什么问题,只是这个关注按钮需要在页面完全载入后才能取到,js通常会在页面载入后但未完全载入成功前执行,所以这个关注按钮就取不出来,你在调用这个函数时要添加一个监听,如下就可以取到关注的button了document.onreadystatechange=function(){if(document.readyState == 'complete')clickButton()}复制代码
Copyright & KaFan & All Rights Reserved.
Powered by Discuz! X3.1( 苏ICP备号 ) GMT+8,H5页面适配所有iPhone和安卓机型的六个技巧
目前,很多APP设计师小伙伴已经开始转向H5前端开发啦,但是解决所有iPhone和安卓机型的适配问题是我们的重中之重。无论是设计APP还是写前端H5.都是要考虑移动端的兼容性。
25学堂今天跟大家来回顾一下H5页面去适配所有iPhone和安卓机型的一些技巧和办法。
回归正题,兼容iphone各版本机型最佳的方式就是自适应。
1、viewport 简单粗暴的方式:
&meta name=&viewport& content=&width=320,maximum-scale=1.3,user-scalable=no&&
直接设置viewport为320px的1.3倍,将页面放大1.3倍。
为什么是1.3?
目前大部分页面都是以320px为基准的布局,而iphone6的宽度比是375/320 = 1.171875,iphone6+则是 414/320 = 1.29375那么以1.29倍也就约等于1.3了。
2、ip6+ 的CSS media query
@media (min-device-width : 375px) and (max-device-width : 667px) and (-webkit-min-device-pixel-ratio : 2){
/*iphone 6*/}@media (min-device-width : 414px) and (max-device-width : 736px) and (-webkit-min-device-pixel-ratio : 3){
/*iphone 6 plus*/}
PS: 也可以直接使用实际的device-width:如 device-width : 375px
在原有页面的基础上,再针对相应的屏幕大小单独写样式做适配。
3、REM布局
REM是CSS3新增的一种单位,并且移动端的支持度很高,android2.x+,ios5+ 都支持。REM是相对于dom结构的根元素来设置大小,也就是html这个元素。相较于em单位,rem使用上更容易理解及运用。
REM与PX的换算可以查看网址: /prototypes/rem-calculator/
假设,html我们设置font-size:12 也就是说12px相对于1rem,那么18px也就是 18/12 = 1.5rem。
那么我们以320px的设计布局为基准,将html设置为font-size:100px,即100px = 1rem。(设置100px是为了方便计算)那么可以将大部分px单位除以100就可以直接改成rem单位了。
REM如何做响应式布局?
1、如果仅仅是适配ip6+设备,那么使用media query就行。
伪代码如下:
/*320px布局*/html{font-size: 100}body{font-size: 0.14rem /*实际相当于14px*/}/* iphone 6 */@media (min-device-width : 375px) and (max-device-width : 667px) and (-webkit-min-device-pixel-ratio : 2){
html{font-size: 117.1875}}/* iphone6 plus */@media (min-device-width : 414px) and (max-device-width : 736px) and (-webkit-min-device-pixel-ratio : 3){
html{font-size: 129.375}}
这样,在ip6下,也就将页面内的元素放大了1.17倍,ip6+下也就是放大了1.29倍。
2、如果是完全自适应,那么可以通过JS来控制。
(function (doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientW
if (!clientWidth)
docEl.style.fontSize = 100 * (clientWidth / 320) + 'px';
// Abort if browser does not support addEventListener
if (!doc.addEventListener)
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);})(document, window);
页面初始化的时候计算font-size,然后再绑定resize事件。这种效果就和百分比布局一样了。
那么用REM做单位与百分比做单位有什么优势?
主要优势在于能更好的控制元素大小。(一般百分比应用在布局层,一般常见设置为50%,33.3%,25%之类的整数居多,难以运用在复杂的页面小部件内)。但是相比百分比布局,需要借助JS或media query实现,略有一点瑕疵。
4、图片自适应
刚说完REM布局,那么用百分比布局也能实现一样的效果,但是用百分比布局,必须要面临一个问题:图片宽度100%,页面加载时会存在高度塌陷的问题。.
如图:页面加载时图片高度默认不存在。
那么可以用padding-top设置百分比值来实现自适应。
公式如下:
padding-top = (Image Height / Image Width) * 100%
原理:padding-top值为百分比时,取值是是相对于宽度的。
相关代码实现:
&div class=&cover&&
&img src=&http://g./bao/uploaded/i1/TB1d6QqGpXXXXbKXXXXXXXXXXXX_!!0-item_pic.jpg_160x160q90.jpg& alt=&&/&&/div&
.cover{position: padding-top: 100%; height: 0; overflow:}.cover img{position: top: 0; width: 100%;}
5、图片高清化
大家都知道,iphone6 plus 是3倍高清图了,它的devicePixelRatio = 3。
关于DPR的介绍可以查看这篇文章《 设备像素比devicePixelRatio简单介绍 》
在ios8下,已经开始支持img的 srcset 属性了(目前移动端也就ios8开始支持),也就是说,可以对一张图片设置2个URL,浏览器自动加载对应的图片。
黄色表示仅支持旧的srcset规范,绿色表示支持全新的srcset规范,包括sizes属性,w描述符。 这里不展开,详细了解可自行google。
如下DEMO,请切换devicePixelRatio值进行查看:
不过目前前端这边图片的实现基本都用lazyload的方式实现。srcset的图片加载方式在实际项目中运用还比较少。
6、背景图高清化
media query 实现高清化
img标签的高清化,可以通过JS判断devicePixelRatio的值来加载不同尺寸的图片,但是对于背景图,写在CSS中的,用JS来判断就略麻烦了,还好CSS通过media query也能判断dpr。
目前兼容性最好的背景图高清化实现方式,使用media query的 -webkit-min-device-pixel-ratio 做判断:
/* 普通显示屏(设备像素比例小于等于1)使用1倍的图 */
background-image: url(img_1x.png);
/* 高清显示屏(设备像素比例大于等于2)使用2倍图
@media only screen and (-webkit-min-device-pixel-ratio:2){
background-image: url(img_2x.png);
/* 高清显示屏(设备像素比例大于等于3)使用3倍图
@media only screen and (-webkit-min-device-pixel-ratio:3){
background-image: url(img_3x.png);
进一步,可以通过工具生成相应的3x,2x,1x的图片及css,在使用时直接引用即可。谁搞一个?
关于移动设备的 -webkit-min-device-pixel-ratio 值,可以查看该网页的整理: /articles/min-device-pixel-ratio/
image-set 实现高清化
image-set,它是Webkit的私有属性,也是Css4的一个属性,它是为了解决Retina屏幕下的图像显示而生。
使用方式也很简单。伪代码如下:
background-image: url(1x.png);
/*不支持image-set的情况下显示*/
background: -webkit-image-set(
url(1x.png) 1x,/* 支持image-set的浏览器的[普通屏幕]下 */
url(2x.png) 2x,/* 支持image-set的浏览器的[2倍Retina屏幕] */
url(3x.png) 3x/* 支持image-set的浏览器的[3倍Retina屏幕] */
目前移动端的支持程度来看,ios7+,android 4.4+ 下已经支持了。如果仅仅是做ip6+的高清适配方案。 image-set 也是一种实现方案。
使用image-set 与 media query 实现有什么区别及好处?
这篇文章里面做了很详细的阐述,大家可以看看:
/safari-6-and-chrome-21-add-image-set-to-support-retina-images/
大体的意思是:image-set不需要告诉浏览器使用什么图像,而是直接提供了图像让浏览器选择。这就意味着,如果在低网速下,浏览器可以选择加载低分辨率的图片。(PS:好智能的样子)
但是相比如media query的实现,image-set仅支持单个图片的高清化,不适合在css sprite下使用。 并且兼容性也是一大硬伤。
一般来说,用在LOGO区域,单个图片图标的区域下,也是个不错的选择。
关于图片列表适配,也就是要让布局更灵活,在电商网站里面,商品列表是一个非常常见的结构。 一种比较智能的列表方式是:两端对齐,间距自适应。
那么可以使用FLEXBOX布局来实现两端对齐的效果,也可以使用 text-align:justify 的方式实现。
具体实现办法: /inline-block-justify/
以上内容是非常适合想要学习H5页面的童鞋们,算是H5页面开发的入门教程。
最新教程周点击榜
微信扫一扫<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&javaWeb用户权限控制简单实现过程
作者:Paulangsky
字体:[ ] 类型:转载 时间:
这篇文章主要为大家详细介绍了javaWeb用户权限控制简单实现过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
最近在做一个网站类型的项目,要对用户的访问模块(权限)进行控制,所以设计并实现了一套简单的权限控制功能。&
1. 数据库设计&
用户:users&
模块:modules
Target Server Type : MYSQL
Target Server Version : 50628
File Encoding
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `modules`
-- ----------------------------
DROP TABLE IF EXISTS `modules`;
CREATE TABLE `modules` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`module` varchar(30) DEFAULT NULL COMMENT '模块',
`pid` int(10) DEFAULT NULL COMMENT '上一级id',
`level` int(4) DEFAULT NULL COMMENT '级别',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of modules
-- ----------------------------
-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`user_code` varchar(10) NOT NULL COMMENT '用户代码',
`user_name` varchar(40) DEFAULT NULL COMMENT '用户名',
`user_password` varchar(100) DEFAULT NULL COMMENT '密码',
`qq` varchar(15) DEFAULT NULL COMMENT 'qq',
`msn` varchar(50) DEFAULT NULL COMMENT 'msn',
`demo` varchar(100) DEFAULT NULL COMMENT '备注',
`auth_code` text COMMENT '权限码',
PRIMARY KEY (`user_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of users
-- ----------------------------
1. 后端实现
&项目中用SSM+freemarker框架,把权限封装成权限树的数据结构,然后转成json格式。&
1) 展示层采用ztree树(setUserauthOnTree.html)
&!DOCTYPE html&
&#include "common/res.html" /&
&script src="${base.ctx}/js/layer-v2.1/laypage/laypage.js"&&/script&
&link href="${base.ctx}/js/layer-v2.1/laypage/skin/laypage.css" rel="stylesheet" type="text/css"/&
&script src="${base.ctx}/js/layer-v2.1/layer/layer.js"&&/script&
&!-- 引入树形菜单样式 --&
&link href="${base.ctx}/component/ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" /&
&script type="text/javascript" src="${base.ctx}/component/ztree/js/jquery.ztree.core-3.5.js"&&/script&
&script type="text/javascript" src="${base.ctx}/component/ztree/js/jquery.ztree.excheck-3.5.js"&&/script&
&style type="text/css"&
.blue-madison {
border: 1px solid #7ca7
border-top: 0;
.caption {
background-color: #578
border-bottom: 0;
padding: 0 10
margin-bottom: 0;
&div class="portlet-body" style="overflow-y: width:400 height:550"&
&div id="ztree" &
&ul id="treeDemo" class="ztree"&&/ul&
&div class="form-actions"&
&div class="row"&
&div class="col-sm-12" align="center" style="margin-top: 5px"&
&button type='button' class="btn btn-primary"
onclick="editModle()"&确定&/button&
&button type="button" class="btn btn-primary" id="cancel"&关闭&/button&
$("document").ready(function() {
type : "post",
url : "${base.ctx}/Setup/getUserRightMaskById",
data:{"id":"${userId}"},
dataType : "json",
success : function(result) {
zTreeObj = $.fn.zTree.init($("#treeDemo"), setting,result.datas.data);
zTreeObj.expandAll(true);
error : function() {
var zTreeO
// zTree 的参数配置,深入使用请参考 API 文档(setting 配置详解)
var setting = {
//dblClickExpand : false,
showLine : true,
//是否显示节点间的连线
enable: true,
//nocheckInherit: false,
chkStyle: "checkbox",
chkboxType: { "Y": "ps", "N": "ps" },
//autoCheckTrigger: true
callback : {
onCheck: zTreeOnCheck,
//checkbox点击的回调事件
function zTreeOnCheck(event, treeId, treeNode) {
/* var zTree = $.fn.zTree.getZTreeObj("treeDemo");
var changedNodes = zTree.getChangeCheckedNodes();
for ( var i=0 ; i & changedNodes. i++ ){
var treeNode = changedNodes[i];
function editModle(){
var rootId=
var midId=
var minId=
var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
var nodes = treeObj.getCheckedNodes();
for(var i=0;i&nodes.i++){
if(nodes[i].level==0){
rootId=rootId+","+nodes[i].
if(nodes[i].level==1){
midId=midId+","+nodes[i].
if(nodes[i].level==2){
minId=minId+","+nodes[i].
if(rootId!=null){
rootId=rootId.substring(5,rootId.length);
if(midId!=null){
midId=midId.substring(5,midId.length);
if(minId!=null){
minId=minId.substring(5,minId.length);
type : "post",
url : "${base.ctx}/Setup/updateUserRightMaskByAjax",
dataType : "json",
data:{"rootId":rootId,"midId":midId,"minId":minId,"userId":"${userId}"},
success : function(result) {
if(result=="1"){
layer.msg("赋权成功!");
setTimeout(function(){top.dialog.get("set-dialog").close().remove();} , 600);
error : function() {
layer.msg("系统错误,请联系管理员!");
$("#cancel").click(function() {
top.dialog.get("set-dialog").close().remove();
展示效果如下:
2) controller控制层用springmvc&
在控制层把数据转成json格式,发到展示层。
* @fun 获取分店用户权限
* @author 皮锋
* @param session
* @param id
* @param substoreid
@RequestMapping("getUserRightMaskById")
@ResponseBody
public Object getUserRightMaskById(HttpSession session,String id,String substoreid){
substoreid=StringUtils.isEmpty(substoreid)&#63;String.valueOf(session.getAttribute("substoreid")):
//判断是酒店还是客栈
List&Map&String, Object&& versionsList=this.setupService.getHotelHotelVersions(substoreid);
Object versions=versionsList.get(0).get("versions");
Map&String, Object& hotelMap=new HashMap&String, Object&();
if((null!=versionsList)&&(versionsList.size()!=0)){ //list不为空
if("complete".equals(versions)){ //酒店
//查询酒店权限树
hotelMap=this.rightMaskService.getUserRightMaskOnTree(substoreid,id,"complete");
}else if("simple".equals(versions)){ //客栈
//查询客栈权限树
hotelMap=this.rightMaskService.getUserRightMaskOnTree(substoreid,id,"simple");
Map&String, Object& resultMap = new HashMap&String, Object&();
resultMap.put("datas", hotelMap);
return JSONObject.toJSONString(resultMap, SerializerFeature.WriteMapNullValue);
3)service服务层把权限封装成满足ztree格式的树数据结构
* @fun 获取分店用户权限
* @author 皮锋
* @param substoreid
* @param id
* @param versions
* @return Map&String, Object&
public Map&String, Object& getUserRightMaskOnTree(String substoreid, String id, String versions) {
Map&String, Object& userRightMask=this.iRightMaskDao.getUserRightMaskBySubAndId(substoreid,id);
List&Map&String, Object&& listOne = new ArrayList&Map&String,Object&&();
List&Map&String, Object&& listTwo = new ArrayList&Map&String,Object&&();
//List&Map&String, Object&& listThree = new ArrayList&Map&String,Object&&();
List&Map&String, Object&& resultList = new ArrayList&Map&String, Object&&();
if(versions.equals("complete")){ //酒店
listOne = this.iRightMaskDao.getRightMaskOnHotelOne();
listTwo = this.iRightMaskDao.getRightMaskOnHotelTwo();
//listThree = this.iRightMaskDao.getRightMaskOnHotelThree();
packagingToTwoTree(resultList,listOne,listTwo,userRightMask);
}else if(versions.equals("simple")){ //客栈
listOne = this.iRightMaskDao.getRightMaskOnTavernOne();
listTwo = this.iRightMaskDao.getRightMaskOnTavernTwo();
//listThree = this.iRightMaskDao.getRightMaskOnTavernThree();
packagingToTwoTree(resultList,listOne,listTwo,userRightMask);
Map&String, Object& map = new HashMap&String, Object&();
map.put("data", resultList);
* @function 封装一个一级树
* @author 皮锋
* @param resultList
* @param listOne
* @param authCode
* @return void
private void packagingToOneTree(List&Map&String, Object&& resultList,
List&Map&String, Object&& listOne, Map&String, Object& authCode) {
for (int i = 0; i & listOne.size(); i++) {
Map&String, Object& rootMap = new HashMap&String, Object&();
rootMap.put("id", listOne.get(i).get("id"));
rootMap.put("name", listOne.get(i).get("module"));
if (validateRightMask(listOne, authCode, i) != -1) {
rootMap.put("checked", true);
rootMap.put("checked", false);
resultList.add(rootMap);
* @function 封装一个二级树
* @author 皮锋
* @param resultList
* @param listOne
* @param listTwo
* @param authCode
* @return void
private void packagingToTwoTree(List&Map&String, Object&& resultList,
List&Map&String, Object&& listOne,
List&Map&String, Object&& listTwo, Map&String, Object& authCode) {
for (int i = 0; i & listOne.size(); i++) {
List&Map&String, Object&& midList = new ArrayList&Map&String, Object&&();
for (int j = 0; j & listTwo.size(); j++) {
if (listTwo.get(j).get("pid").toString()
.equals(listOne.get(i).get("id").toString())) {
List&Map&String, Object&& minlist = new ArrayList&Map&String, Object&&();
Map&String, Object& midMap = new HashMap&String, Object&();
midMap.put("id", listTwo.get(j).get("id"));
midMap.put("name", listTwo.get(j).get("module"));
midMap.put("children", minlist);
if (validateRightMask(listTwo, authCode, j) != -1) {
midMap.put("checked", true);
midMap.put("checked", false);
midList.add(midMap);
Map&String, Object& rootMap = new HashMap&String, Object&();
rootMap.put("id", listOne.get(i).get("id"));
rootMap.put("name", listOne.get(i).get("module"));
rootMap.put("children", midList);
if (validateRightMask(listOne, authCode, i) != -1) {
rootMap.put("checked", true);
rootMap.put("checked", false);
resultList.add(rootMap);
* @function 封装一个三级树
* @author 皮锋
* @param resultList
* @param listOne
* @param listTwo
* @param listThree
* @param authCode
* @return void
private void packagingToThreeTree(List&Map&String, Object&& resultList,
List&Map&String, Object&& listOne,
List&Map&String, Object&& listTwo,
List&Map&String, Object&& listThree, Map&String, Object& authCode) {
for (int i = 0; i & listOne.size(); i++) {
List&Map&String, Object&& midList = new ArrayList&Map&String, Object&&();
for (int j = 0; j & listTwo.size(); j++) {
if (listTwo.get(j).get("pid").toString()
.equals(listOne.get(i).get("id").toString())) {
List&Map&String, Object&& minlist = new ArrayList&Map&String, Object&&();
for (int k = 0; k & listThree.size(); k++) {
Map&String, Object& minMap = new HashMap&String, Object&();
if (listThree.get(k).get("pid").toString()
.equals(listTwo.get(j).get("id").toString())) {
minMap.put("id", listThree.get(k).get("id"));
minMap.put("name", listThree.get(k).get("module"));
if (validateRightMask(listThree, authCode, k) != -1) {
minMap.put("checked", true);
minMap.put("checked", false);
minlist.add(minMap);
Map&String, Object& midMap = new HashMap&String, Object&();
midMap.put("id", listTwo.get(j).get("id"));
midMap.put("name", listTwo.get(j).get("module"));
midMap.put("children", minlist);
if (validateRightMask(listTwo, authCode, j) != -1) {
midMap.put("checked", true);
midMap.put("checked", false);
midList.add(midMap);
Map&String, Object& rootMap = new HashMap&String, Object&();
rootMap.put("id", listOne.get(i).get("id"));
rootMap.put("name", listOne.get(i).get("module"));
rootMap.put("children", midList);
if (validateRightMask(listOne, authCode, i) != -1) {
rootMap.put("checked", true);
rootMap.put("checked", false);
resultList.add(rootMap);
* @function 验证authCode中是否有list中的权限码
* @author 皮锋
* @param list
* @param authCode
* @param i
* @return int
private int validateRightMask(List&Map&String, Object&& list,
Map&String, Object& authCode, int i) {
String rightMask = authCode.get("auth_code") != null &#63; authCode.get(
"auth_code").toString() : "";
if (!StringUtils.isEmpty(rightMask)) {
rightMask = rightMask.replace(";", ",");
String[] arry = rightMask.split(",");
for (int j = 0; j & arry. j++) {
String arryRightMask = arry[j];
String listRightMask = list.get(i).get("id").toString();
if (arryRightMask.equals(listRightMask)) {
return -1;
return -1;
4) dao层查询数据库获得用户权限&
a.在数据层按权限级别从modules表中分别拿出不同级别的权限&
select id,module,pid,level from modules where level='0'
select id,module,pid,level from modules where level='1'
select id,module,pid,level from modules where level='2'
b.在users表中拿出某用户的所有权限(权限码)&
select auth_code from users where user_code='pifeng'&
c.保存权限时不同级别之间的权限码用英式分号“;”隔开,同一级别之间的权限码用英式逗号“,”隔开。例如:1,2,3,4,5,6,7,8,9,10,11,12;13,14,15,16,17,18,19,20,21,22,23,24,25,26,36,37,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,62,63,64,133,65,66,67,68,69,70,71,72,73,74,75,126,127,128,129,130,131,76,77,78,79,80,81,82,83,84,85,86,87,88,99,124,134,135,136,140,141,89,90,91,92,93,94,95,96,97,98,137,138,139,100,101,102,103,106,107,132,108,109,110,111,112,113,114,115,116,125,117,118,119,120,121,122&
5)根据用户的权限码用freemarker标签控制页面功能模块是否显示&
a.freemarker在xml文件中的配置
&bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"&
&!--模板加载路径--&
&property name="templateLoaderPath"&
&value&/WEB-INF/ftl/&/value&
&/property&
&property name="freemarkerVariables"&
&entry key="xml_escape" value-ref="fmXmlEscape"/&
&/property&
&property name="freemarkerSettings"&
&prop key="tag_syntax"&auto_detect&/prop&
&prop key="template_update_delay"&0&/prop&
&prop key="default_encoding"&UTF-8&/prop&
&prop key="output_encoding"&UTF-8&/prop&
&prop key="locale"&zh_CN&/prop&
&prop key="date_format"&yyyy-MM-dd&/prop&
&prop key="time_format"&HH:mm:ss&/prop&
&prop key="number_format"&0.######&/prop&
&prop key="datetime_format"&yyyy-MM-dd HH:mm:ss&/prop&
&!--空值处理--&
&prop key="classic_compatible"&true&/prop&
&!--自动导入ftl模板,并以“base”别名作为命名空间--&
&prop key="auto_import"&inc/spring.ftl as base&/prop&
&/property&
&bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/&
&bean id="freeMarkerViewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"&
&property name="suffix" value=".html"/&
&property name="cache" value="false"/&
&property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/&
&property name="contentType" value="text/charset=UTF-8"&&/property&
&!--fixed Exception:Cannot expose session attribute 'substoreid' because of an existing model --&
&property name="allowSessionOverride" value="true"/&
&property name="exposeRequestAttributes" value="true"/&
&property name="exposeSessionAttributes" value="true"/&
&property name="exposeSpringMacroHelpers" value="true"/&
&!-- 此变量值为pageContext.request, 页面使用方法:request.contextPath --&
&property name="requestContextAttribute" value="request"/&
&property name="attributesMap"&
&!-- 定义Freemarker方法的名称 --&
&entry key="menucall"&
&!-- 关联到我们之前定义的工具类 --&
&bean class="com.leike.util.MenuFunction" /&
&/property&
b.写个类继承TemplateMethodModel类,实现freemarker自定义方法,用于实现控制页面模块是否显示&
登陆的时候把用户权限码存入session中,然后从session中取权限。下面是一个例子:
public class MenuFunction implements TemplateMethodModel{
public Object exec(List arg0) throws TemplateModelException {
int level = Integer.valueOf(arg0.get(0).toString()); //模块等级
int modelId=Integer.valueOf(arg0.get(1).toString()); //模块id
int count=0; //记录session是否有此模块的权限码
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session=request.getSession();
Object o = session.getAttribute("info");
if(o==null)
Info info = (Info)
String authCode=info.getUser().getAuthCode(); //权限码
if(authCode.contains(";")){
String[] masks=authCode.split(";");
String[] m=masks[level].split(",");
for (int i = 0; i & m. i++) {
if(modelId==Integer.parseInt(m[i])){
if(count==0){
c.在页面使用freemarker标签,控制模块的显示隐藏&
Menucall中的两个参数,第一个为模块等级,第二个为模块的id&
&#if menucall(1,122)&
&li style="line-height: 250%"&
&a href="#" id="booknew"&&i class="glyphicon"&&/i&预订&/a&
以上就是对用户的访问模块(权限)进行控制的大体实现。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 h5实现分享功能 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信