首页> 标签> 数据安全/隐私保护
"数据安全/隐私保护"
共 63909 条结果
全部 问答 文章 公开课 课程 电子书 技术圈 体验
【收集】【Linux】记录常用的操作指令 不定时更新
目录【查询软件版本安装软件指令】【进程的相关指令】【管道】【文件相关指令】【目录相关操作】【服务管理】【解压打包操作】【系统操作】【编译器】【名词的含义】【查询软件版本安装软件指令】【查询指令】 rpm -qa | grep jdk【安装指令】 yum install java-1.8.0-openjdk【卸载指令】 yum -y remove java-1.8.0-openjdk【删除指令】 rm -rf 目录名字【退出指令】 exit(注:安装JDK时一般先查询,根据查询结果进行安装)【进程的相关指令】【查svn进程指令】ps -ef|grep svn【查询当前目录下的目录里的文件数量】 wc -l */*【查询端口3306号】netstat -tunlp | grep 3306【查找mysql指令】rpm -qa | grep mysql【删除mysql指令】rpm -e mysq --nodeps-e参数表示删除 --nodeps表示不校验依赖关系top再按c键是查看详细进程的路径按u是查询用户名操作者按k是输入PID达到关闭哪个进程,输入好PID回车后,还会需要输入9,回车就关闭了。按Ctrl键+C键,结束查看或者记住PID,结束查看了之后关闭0602编号的进程kill 0602强制关闭0602编号的进程kill -9 0602【管道】作用将一个命令的输出用作另一个命令的输入。分页查询帮助信息ls -help | more 分页查询帮助信息查询名称中包含java的进程ps -ef | grep javaip更多相关的信息ifconfig | more【文件相关指令】【查看文件内容指令】显示a.txt文件的内容cat a.txt查看home目录下a.txt文件后10行的内容tail -10 /home/a.txt动态查看a.log日志(*)tail -f a.logCtrl键+C键 结束查看【识别文件类型】识别a.html的文件类型file a.html【查找符合条件的文件】查找文件名称以nanfangzhe开头的文件find / -name "nanfangzhe*" -ls查找文件名称以包含fangzhe的文件find / -name "\*fangzhe\*" -ls查找文件名称以.tar.gz结尾的文件find / -name "\*.tar.gz" -ls查询当前目录和子目录下所有最近 2 天内更新过的文件列出find . -ctime -2【文件操作】创建a.txt文件touch a.txta.txt文件复制成b.txt文件cp a.txt b.txt复制a.txt文件和b.txt到当前目录下的dir目录(dir目录必须要在当前目录下存在)cp a.txt b.txt dir复制a.txt文件和b.txt到根目录下的其他子目录(目录都必须要存在)cp a.txt b.txt /home/develop/a.txt文件重命名、修改文件名b.jsmv a.txt b.js把a.txt文件移动到bdir目录下mv a.txt bdir查看文件,除了隐藏的文件(在Linux中,以.开头的都是隐藏文件)ls查看所有文件或目录(包括隐藏的文件)ls -a查看文件的具体情况和权限情况ls -l 缩写是 ll清楚a.log日志文件里的数据> a.log【文件权限操作】① u:user 属主 ② g:group 属组 ③ o:other 其他用户④ r:可读取内容 ⑤ w:可修改 ⑥ x:可运行修改a.txt文件的所有人都可读可写可运行权限chmod 777 a.txtchmod u=rwx,g=rwx,o=rwx a.txt【查询所有文件】ls -a 或 ll -a (查询所有文件,包括在编辑的文件变成了隐藏的文件)【删除在编译的a.txt文件】rm -rf .a.txt.swp【目录相关操作】回到上一层目录cd …回到根目录(类似Windows系统的回到我的电脑)cd /回到用户主目录cd ~回到上一个所在的目录cd -显示当前目录pwd在当前目录下创建develop目录mkdir develop在当前目录下创建a目录和b子目录mkdir -p a/b删除空目录armdir a删除a目录下的b目录下的空目录c(必须c是空目录,并且c被删除后,b目录也变成空目录,b目录被删除后,a目录也必须是空目录,方能用)rmdir -p a/b/c直接干掉 直接删除 a目录rm -rf a直接干掉 直接删除 a.html文件rm -rf a.html【服务管理】列出所有端口netstat -ntlp想知道端口被哪个进程占用,可以查看进程的详细信息,假设该端口被占用的PID是0602。ps 0602想用被占用的端口,只要kill掉被占用的端口的PID就好了,假设PID是0602。kill 0602【解压打包操作】把当前目录下所有的文件打包成nanfangzhe.tartar -cvf nanfangzhe.tar ./*把当前目录下的a.txt和index.html打包并压缩成nafangzhe.tar.gztar -cvf nanfangzhe.tar.gz ./a.txt ./index.html解压abcd.tartar -xvf abcd.tar解压abcd.tar.gz 到/home/develop目录下tar -zxvf abcd.tar.gz -C /home/develop其中,-cvf的意思是创建一个新tar文件,并显示运行过程的信息和指定文件夹名-c:创建一个新tar文件-v:显示运行过程的信息-f:指定文件名-z:调用gzip压缩命令进行压缩-t:查看压缩文件的内容-x:解开tar文件(注:-x不能解压.gz压缩类型的,-z不能解压.tar压缩类型的)解压a.zip文件unzip a.zip【系统操作】【添加用户】Linux添加用户并授权ROOT管理权限添加用户叫developadduser develop为用户develop添加密码passwd develop会提示你输入两次密码develop将用户加入管理权限组usermod -a -G wheel develop修改sudoers文件为可修改状态chmod -v u+w /etc/sudoers在sudoers文件里新增一行命令,使develop用户和Root一样权限。(添加:develop ALL=(ALL) ALL)vim /etc/sudoer把sudoers文件修改回只读模式chmod -v u-w /etc/sudoers【清屏】clearCrtl键 + L键【查看硬盘剩余空间】查看磁盘使用情况df查看磁盘使用详细的情况df -lh全部硬盘的使用与剩余情况df -a【搜索文件里的内容】搜索内容include,在etc目录下的nginx目录下的nginx.conf文本中的行内容和行数grep -n "include" /etc/nginx/nginx.conf监控符合a.log日志有nanfangzhe内容的tail -f a.log | grep "nanfangzhe"【查看之前执行的指令】查看最近执行的十条指令history 10查看历史执行的指令中带有a.txt内容的指令history | grep a.txt-c:清空当前历史命令;-a:将历史命令缓冲区中命令写入历史命令文件【/root/.bash_history】;-r:将历史命令文件中的命令读入当前历史命令缓冲区;-w:将当前历史命令缓冲区命令写入历史命令文件中【/root/.bash_history】;n:打印最近的n条历史命令【编译器】vim编译器(相当于vi的升级版,更推荐使用vim)修改根目录下home目录下的a.txt文件的内容vim /home/a.txt按下面的情况按键盘时的作用字母说明小写i键在当前位置前插入大写I键在当前行首插入a键在当前位置后插入A键在当前行尾插入o键在当前行尾后插入一行O键在当前行首插入一行ESC键退出插入模式Shift键+;键 按出:(冒号)进入到底行模式,此时输入wq,然后回车,就保存退出了。 (输入q!,然后回车是不保存退出。)dd快速删除一行yy复制当前行yny当前行和向后复制n行p在当行插入所复制的行r替换单个字符u(小写)undo 的第 1 个字母,功能是撤销最近一次对文本做的修改操作。Ctrl+RRedo 的第 1 个字母,功能是恢复最近一次所做的撤销操作。U(大写)第一次会撤销对一行文本(光标所在行)做过的全部操作,第二次使用该命令会恢复对该行文本做过的所有操作。/(回车后会高亮所有的匹配文)/后跟查找的字符串。vim会显示文本中第一个出现的字符串。?(回车后会高亮所有的匹配文)?后跟查找的字符串。vim会显示文本中最后一个出现的字符串。n查找字符串的下一个匹配N查找字符串的上一个匹配【名词的含义】字母含义#1. 在输入命令行前代表是root用户,如果是普通用户,输入命令行前的字符是$ 2. 在脚本里是指申明变量如有其他问题存在,请各路山居隐士指点一二。
文章
监控  ·  Java  ·  关系型数据库  ·  MySQL  ·  编译器  ·  Linux  ·  应用服务中间件  ·  开发工具  ·  数据安全/隐私保护  ·  nginx
2022-05-17
Google Pay支付遇到的问题(下)
Google Play 接受的付款方式注意事项信用卡或借记卡        注意:通过 Google Play 接受的卡片类型可能会有所不同。如果您的卡在您认为应该时无法使用,请联系您的银行或发卡机构寻求帮助。使用信用卡或借记卡时,您可能会注意到帐户上的临时授权。手机计费        注意: 当您注册手机帐单时,您可能会在手机上看到以“DCB”或“DCB_Association”开头的 SMS(文本消息)。该消息会自动生成并发送,以完成您 Google Play 帐户的手机帐单注册。 手机计费疑难解答如果您没有看到运营商代扣选项,请记住:手机帐单仅可使用 Google Play 商店应用程序进行。它在计算机或移动浏览器上的 Google Play 网站上不可用。您在运营商处的帐户必须信誉良好。如果您使用带有双 SIM 卡的设备,请确保将正确的 SIM 卡放入插槽 1,并将插槽 2 留空。移动电话计费在有 root 权限的设备上不可用。某些移动电话运营商不能用于支付订阅费用。请咨询您的运营商以确保:您没有超过运营商的每月支出限额。您的设备和服务计划允许购买高级内容。您的设备可以使用手机计费。取消的购买        未成功获得运营商授权的购买将立即取消。如需有关不成功的移动电话账单购买的帮助,请联系您的移动服务提供商。电子钱包        您可以使用 Touch 'n Go Wallet 在 Google Play 上购买应用程序和数字内容。您需要有足够余额的已注册Touch 'n Go 钱包帐户才能在 Google Play 上使用此服务。查找您可以使用的付款方式        可用的付款方式因国家/地区而异。     Google Play登录报错做Google Play登录获取不到用户信息Google Play登录        1.查看凿洞网络是否开启(12501)        2.查看代码是否有误        3.查看此应用是否加入Google Play应用签名计划 如果加入涉及三方的都要使用应用签名证书下的资料        例:google登录中开发者账号>API权限>关联的项目>选中你的关联项目例:facebook中登录的keyhash要做调整        但是:打包时还是用原来的jks文件使用firebaseFacebook登录做Facebook登录获取不到用户信息        前提是测试时正常,发版后查看keyhash配制是否正确提示:"登录错误:登录此应用程序时出错。请稍后再试。"        1.简单的临时解决方案是从您连接的Facebook应用程序中删除Deezer,并使用您的Facebook帐户重新连接到Deezer,该帐户无法更改您的密码。至少这适用于使用Facebook创建的Spotify帐户,现在也存在这个问题。        2.keyhash配制是否正确        keyhash可多个并存        web和app应用,或者打包电脑不同存在多个keyhash        web获取方式,直接打开会给一个keyhash        app应用:            1:keytool -exportcert -alias androiddebugkey -keystore "C:\Users\USERNAME\.android\debug.keystore" | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" base64        注:openssl不是内部或外部命令        2:放在自己的Activity界面运行生成try { PackageInfo info = getPackageManager().getPackageInfo( "com.ceshi.demo", PackageManager.GET_SIGNATURES); for (Signature signature : info.signatures) { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(signature.toByteArray()); Log.e("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT)); } } catch (PackageManager.NameNotFoundException e) { } catch (NoSuchAlgorithmException e) { }谷歌提问让应用商店详情的介绍文字更改颜色答:在编辑文字时,加入 html 的色彩编码。例如:您的文字 参考链接:快去找吧预注册数量没有变化答:有一定的数量要求,未达到数量要求则会一直显示为0预注册:        在后台的预注册数量数据,每日更新时间为PST 12点。若您在此时间吴看到任何数据更新,便代表预注册人数低于一定数值因而没显现出来,因此请您等待几小时后再查看。相关推荐Mycard支付ONE store支付Google Pay接入aab打包
文章
Go  ·  API  ·  数据安全/隐私保护  ·  Android开发  ·  开发者
2022-05-17
11.2 Java 字符串相关类使用
Java中 Character、String、StringBuilder 等类用于文本处理,它们的基础都是 char。字符编码基础ASCII 码最高位设置为 0,用剩下的 7 位表示字符。这 7 位可以看作数字 0~127。数字 32~126 表示的字符都是可打印字符,0~31 和 127 表示不可以打印的字符,这些字符一般用于控制目的,这些字符中大部分都是不常用的。数字 32~126 的含义,如图2-1所示,除了中文之外,我们平常用的字符基本都涵盖了,键盘上的字符大部分也都涵盖了。ISO 8859-1最高位为1,ISO 8859-1又称 Latin-1,它也是使用一个字节表示一个字符,其中 0~127 与 ASCII 一样,128~255 规定了不同的含义。在128~255中,128~159 表示一些控制字符,这些字符也不常用,就不介绍了。160~255 表示一些西欧字符。Windows-1252ISO 8859-1 虽然号称是标准,用于西欧国家,但它连欧元(€)这个符号都没有,因为欧元比较晚,而标准比较早。实际中使用更为广泛的是Windows-1252 编码,这个编码与 ISO 8859-1 基本是一样的,区别只在于数字 128~159。Windows-1252 使用其中的一些数字表示可打印字符。这个编码中加入了欧元符号以及一些其他常用的字符。基本上可以认为,ISO 8859-1 已被 Windows-1252 取代,在很多应用程序中,即使文件声明它采用的是 ISO 8859-1编码,解析的时候依然被当作 Windows-1252 编码。我国内地的三个主要编码 GB2312、GBK、GB18030 有时间先后关系,表示的字符数越来越多,且后面的兼容前面的,GB2312 和 GBK 都是用两个字节表示,而 GB18030 则使用两个或四个字节表示。我国香港特别行政区和我国台湾地区的主要编码是 Big5。如果文本里的字符都是 ASCII 码字符,那么采用以上所说的任一编码方式都是一样的。但如果有高位为 1 的字符,除了 GB2312、GBK、GB18030外,其他编码都是不兼容的。比如,Windows-1252 和中文的各种编码是不兼容的,即使 Big5 和 GB18030 都能表示繁体字,其表示方式也是不一样的,而这就会出现所谓的乱码,具体我们稍后介绍。Unicode 编码Unicode 给世界上每个字符分配了一个编号,编号范围为 0x000000~0x10FFFF。编号范围在 0x0000~0xFFFF 的字符为常用字符集,即 65 536个数字之内,称BMP(Basic Multilingual Plane)字符。编号范围在 0x10000~0x10FFFF 的字符叫做增补字符(supplementary character)。每个字符都有一个Unicode编号,这个编号一般写成十六进制,在前面加U+。大部分中文的编号范围为 U+4E00~U+9FFF,例如,“马”的 Unicode是 U+9A6C。Unicode 主要规定了编号,但没有规定如何把编号映射为二进制。UTF-16 是一种编码方式,或者叫映射方式,它将编号映射为 2 或 4 个字节,对 BMP 字符,它直接用 2 个字节表示,对于增补字符,使用 4 个字节表示,前两个字节叫高代理项(high surrogate),范围为 0xD800~0xDBFF,后两个字节叫低代理项(low surrogate),范围为 0xDC00~0xDFFF。UTF-16 定义了一个公式,可以将编号与 4 字节表示进行相互转换。Java 内部采用 UTF-16 编码,char 表示一个字符,但只能表示 BMP 中的字符,对于增补字符,需要使用两个 char 表示,一个表示高代理项,一个表示低代理项。那编号怎么对应到二进制表示呢?有多种方案,主要有UTF-32、UTF-16和UTF-8。UTF-32 这个最简单,就是字符编号的整数二进制形式,4 个字节。但有个细节,就是字节的排列顺序,如果第一个字节是整数二进制中的最高位,最后一个字节是整数二进制中的最低位,那这种字节序就叫“大端”(Big Endian, BE),否则,就叫“小端”(Little Endian, LE)。对应的编码方式分别是 UTF-32BE 和 UTF-32LE。可以看出,每个字符都用 4 个字节表示,非常浪费空间,实际采用的也比较少。UTF-16UTF-16使用变长字节表示:1)对于编号在U+0000~U+FFFF的字符(常用字符集),直接用两个字节表示。2)字符值在 U+10000~U+10FFFF 的字符(也叫做增补字符集),需要用4个字节表示。前两个字节叫高代理项,范围是 U+D800~U+DBFF;后两个字节叫低代理项,范围是U+DC00~U+DFFF。数字编号和这个二进制表示之间有一个转换算法,这里就不介绍了。区分是两个字节还是 4 个字节表示一个字符就看前两个字节的编号范围,如果是 U+D800~U+DBFF,就是4个字节,否则就是两个字节。UTF-16 也有和 UTF-32 一样的字节序问题,如果高位存放在前面就叫大端(BE),编码就叫 UTF-16BE,否则就叫小端,编码就叫UTF-16LE。UTF-16 常用于系统内部编码,UTF-16 比 UTF-32 节省了很多空间,但是任何一个字符都至少需要两个字节表示,对于美国和西欧国家而言,还是很浪费的。UTF-8UTF-8 使用变长字节表示,每个字符使用的字节个数与其Unicode编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多,使用的字节个数为1~4不等。小于128的,编码与ASCII码一样,最高位为0。其他编号的第一个字节有特殊含义,最高位有几个连续的1就表示用几个字节表示,而其他字节都以10开头。charchar 看上去是很简单的,char 用于表示一个字符,这个字符可以是中文字符,也可以是英文字符。赋值时把常量字符用单引号括起来。在 Java 内部进行字符处理时,采用的都是 Unicode,具体编码格式是UTF-16BE。简单回顾一下,UTF-16 使用 2 个或 4 个字节表示一个字符,Unicode 编号范围在 65536 以内的占两个字节,超出范围的占4个字节,BE 就是先输出高位字节,再输出低位字节,这与整数的内存表示是一致的。char 本质上是一个固定占用两个字节的无符号正整数,这个正整数对应于 Unicode 编号,用于表示那个 Unicode 编号对应的字符。由于固定占用两个字节,char 只能表示 Unicode 编号在 65 536 以内的字符,而不能表示超出范围的字符。那超出范围的字符怎么表示呢?使用两个 char。char 的赋值形式:// 赋值的时候是按当前的编码解读方式,将这个字符形式对应的 Unicode 编号值赋给变量 char c = '蕾'; System.out.println(c); // 赋值方式是按 Unicode 字符形式 c = '\u857e'; System.out.println(c); // Unicode 编号的十六进制表示 c = 0x857e; System.out.println(c); // Unicode 编号的十进制表示 c = 34174; System.out.println(c); // Unicode 编号的二进制表示 c = 0b10000101_01111110; System.out.println(c);char 的加减运算就是按其 Unicode 编号进行运算,一般对字符做加减运算没什么意义,但 ASCII 码字符是有意义的。比如大小写转换,大写A~Z的编号是 65~90,小写 a~z 的编号是 97~122,正好相差 32,所以大写转小写只需加 32,而小写转大写只需减 32。加减运算的另一个应用是加密和解密,将字符进行某种可逆的数学运算可以做加解密。java.lang.String 类Java 中的字符串是由双引号括起来的多个字符,下面示例都是表示字符串常量:String str = "Hello World" String str = "\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064" String str = "世界你好" String str = "A"String 常用的构造方法String():使用空字符串创建并初始化一个新的 String 对象。 String(String original):使用另外一个字符串创建并初始化一个新的 String 对象。 String(StringBuffer buffer):使用可变字符串对象(StringBuffer)创建并初始化一个新的 String 对象。 String(StringBuilder builder):使用可变字符串对象(StringBuilder)创建并初始化一个新的 String 对象。 String(byte[] bytes):使用平台的默认字符集解码指定的 byte 数组,通过 byte 数组创建并初始化一个新的 String 对象。 String(char[] value):通过字符数组创建并初始化一个新的 String 对象。 String(char[] value, int offset, int count):通过字符数组的子数组创建并初始化一个新的 String 对象;offset参数是子数组第一个字符的索引,count 参数指定子数组的长度。关于 String的实现原理,String 类内部用一个字符数组表示字符串。在Java 9对String的实现进行了优化,它的内部不是 char 数组,而是 byte 数组,如果字符都是 ASCII 字符,它就可以使用一个字节表示一个字符,而不用 UTF-16BE 编码,节省内存。String 的查找在给定的字符串中查找字符或字符串是比较常见的操作。在 String 类中提供了 indexOf 和 lastIndexOf 方法用于查找字符或字符串,返回值是查找的字符或字符串所在的位置,-1 表示没有找到。这两个方法有多个重载版本:int indexOf(int ch):从前往后搜索字符 ch,返回第一次找到字符 ch 所在处的索引。 int indexOf(int ch, int fromIndex):从指定的索引开始从前往后搜索字符 ch,返回第一次找到字符ch所在处的索引。 int indexOf(String str):从前往后搜索字符串 str,返回第一次找到字符串所在处的索引。 int indexOf(String str, int fromIndex):从指定的索引开始从前往后搜索字符串 str,返回第一次找到字符串所在处的索引。 int lastIndexOf(int ch):从后往前搜索字符 ch,返回第一次找到字符 ch 所在处的索引。 int lastIndexOf(int ch, int fromIndex):从指定的索引开始从后往前搜索字符ch,返回第一次找到字符ch所在处的索引。 int lastIndexOf(String str):从后往前搜索字符串 str,返回第一次找到字符串所在处的索引。 int lastIndexOf(String str, int fromIndex):从指定的索引开始从后往前搜索字符串 str,返回第一次找到字符串所在处的索引。String 的比较比较相等String 提供的比较字符串相等的方法:boolean equals(Object anObject):比较两个字符串中内容是否相等。boolean equalsIgnoreCase(String anotherString):类似 equals 方法,只是忽略大小写。比较大小 有时不仅需要知道是否相等,还要知道大小,String 提供的比较大小的方法:int compareTo(String anotherString):按字典顺序比较两个字符串(字典中顺序事实上就它的 Unicode 编码)。如果参数字符串等于此字符串,则返回值 0;如果此字符串小于字符串参数,则返回一个小于 0 的值;如果此字符串大于字符串参数,则返回一个大于 0 的值。int compareToIgnoreCase(String str):类似 compareTo,只是忽略大小写。比较前缀和后缀boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束。boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始。String 的字符串截取String substring(int beginIndex):从指定索引 beginIndex 开始截取一直到字符串结束的子字符串。 String substring(int beginIndex, int endIndex):从指定索引 beginIndex 开始截取直到索引 endIndex - 1 处的字符,注意包括索引为 beginIndex 处的字符,但不包括索引为endIndex处的字符。另外,String 还提供了字符串分割方法split(" ")方法,参数是分割字符串,返回值String[]。trim() 返回一个前后不含任何空格的调用字符串的副本String 的+和+=运算符Java中,String 可以直接使用 + 和 += 运算符,这是 Java 编译器提供的支持,背后,Java 编译器一般会生成 StringBuilder, + 和 += 操作会转换为 append。对于简单的情况,可以可以直接使用 String 的 + 和 +=,对于复杂的情况,尤其是有循环的时候,应该直接使用 StringBuilder。可变字符串 StringBuffer 和 StringBuilderJava 提供了两个可变字符串类 StringBuffer 和 StringBuilder,中文翻译为“字符串缓冲区”。StringBuffer 是线程安全的,它的方法是支持线程同步,线程同步会操作串行顺序执行,在单线程环境下会影响效率。StringBuilder 是 StringBuffer 单线程版本,Java 5之后发布的,它不是线程安全的,但它的执行效率很高。StringBuffer 和 StringBuilder 具有完全相同的 API,即构造方法和方法等内容一样。StringBuilder 的中构造方法有4个:StringBuilder():创建字符串内容是空的 StringBuilder 对象,初始容量默认为 16个字符。 StringBuilder(CharSequence seq):指定 CharSequence 字符串创建StringBuilder 对象。CharSequence 接口类型,它的实现类有:String、StringBuffer 和 StringBuilder 等,所以参数 seq 可以是String、StringBuffer 和 StringBuilder 等类型。 StringBuilder(int capacity):创建字符串内容是空的 StringBuilder 对象,初始容量由参数capacity指定的。 StringBuilder(String str):指定String字符串创建 StringBuilder 对象。StringBuffer 的追加、插入、删除和替换字符串追加方法是 append,append 有很多重载方法,可以追加任何类型数据。StringBuilder insert(int offset, String str):在字符串缓冲区中索引为 offset 的字符位置之前插入str,insert 有很多重载方法,可以插入任何类型数据。delete(int start, int end):在字符串缓冲区中删除子字符串,要删除的子字符串从指定索引 start 开始直到索引 end - 1 处的字符。start 和 end 两个参数与 substring(int beginIndex, int endIndex)方法中的两个参数含义一样。replace(int start, int end, String str) 字符串缓冲区中用 str 替换子字符串,子字符串从指定索引 start 开始直到索引 end - 1 处的字符。start 和 end 同 delete(int start, int end)方法。编码转换String内部是按 UTF-16BE 处理字符的,对 BMP 字符,使用一个 char,两个字节,对于增补字符,使用两个 char,四个字节。不同编码可能用于不同的字符集,使用不同的字节数目,以及不同的二进制表示。如何处理这些不同的编码呢?这些编码与 Java 内部表示之间如何相互转换呢?Java 使用 Charset 类表示各种编码,它有两个常用静态方法:Charset.defaultCharset() 和 Charset.forName(String charsetName)。String 类提供了如下方法,返回字符串按给定编码的字节表示:getByte(),getByte(String charsetName),getByte(Charset charset)。字符串乱码问题乱码有两种常见原因:一种比较简单,就是简单的解析错误;另外一种比较复杂,在错误解析的基础上进行了编码转换。简单的解析导致的乱码,之所以看起来是乱码,是因为看待或者说解析数据的方式错了。只要使用正确的编码方式进行解读就可以纠正了。如果怎么改变查看方式都不对,那很有可能就不仅仅是解析二进制的方式不对,而是文本在错误解析的基础上还进行了编码转换。恢复的基本思路是尝试进行逆向操作,假定按一种编码转换方式获取乱码的二进制格式,然后再假定一种编码解读方式解读这个二进制,查看其看上去的形式,这要尝试多种编码,如果能找到看着正常的字符形式,应该就可以恢复。参考Java 编程的逻辑-微信读书https://weread.qq.com/web/reader/b51320f05e159eb51b29226kc81322c012c81e728d9d180
文章
自然语言处理  ·  安全  ·  算法  ·  Java  ·  编译器  ·  API  ·  数据安全/隐私保护  ·  索引
2022-05-17
【JAVA】【Hutool】一行代码就能干的那些事
【所需添加的依赖】<!-- hutool 一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.13</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.13</version> </dependency> <!-- 发送邮箱依赖 --> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency>一、一行代码给图片添加水印【代码与结果展示】public static void main(String[] args) { ImgUtil.pressText(// FileUtil.file("f:/self/pic/w.jpg"), // FileUtil.file("f:/self/pic/w.png"), // "南方者@版权所有", Color.WHITE, //文字 new Font("黑体", Font.BOLD, 100), //字体 0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移 0, //y坐标修正值。 默认在中间,偏移量相对于中间偏移 0.5f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 ); }二、一行代码完成邮箱发送# 发件人(必须正确,否则发送失败) from = nanfangzhe@qq.com# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) pass = q1xxxxwxxx2xxxxe3xxxx【配置文件】在标准Maven项目中为src/main/resources)的config目录下新建mail.setting文件 mail.setting内容:# 发件人(必须正确,否则发送失败)from = nanfangzhe@qq.com# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)pass = q1xxxxwxxx2xxxxe3xxxx【代码与结果展示】public static void main(String[] args) { MailUtil.send("468133838@qq.com", "南方者的一封信", "恭喜你,完成邮箱发送。 南方者的CSDN博客地址:https://blog.csdn.net/qq_43263647", false); }
文章
Java  ·  Maven  ·  数据安全/隐私保护
2022-05-17
MariaDB 简介
MariaDB Community Server 是一个开源的关系数据库服务器,深受全世界开发者的喜爱。由 MySQL 的原始开发者创建,MariaDB 与 MySQL 兼容,并保证永远保持开源。为一些世界上最受欢迎的网站提供动力,比如维基百科和 WordPress.com。它也是全球很多银行、社交媒体、移动和电子商务网站背后的核心引擎。MariaDB Enterprise 是一个完整的生产级开源数据库解决方案。MariaDB 官网https://mariadb.com/官网下载地址https://dlm.mariadb.com/browse/mariadb_server/CENT OS 下安装 MariaDByum install mariadb-server mariadbmariadb数据库的相关命令是:systemctl start mariadb #启动MariaDB systemctl stop mariadb #停止MariaDB systemctl restart mariadb #重启MariaDB systemctl enable mariadb #设置开机启动Windows 下安装 MariaDB我这里选择的是 https://dlm.mariadb.com/1920019/MariaDB/mariadb-10.6.5/winx64-packages/mariadb-10.6.5-winx64.zip 版本。使用 mysql_install_db.exe 命令进行安装mysql_install_db.exe 的功能可以与 Unix 上使用的 shell 脚本 mysql_install_db 相媲美,但是它已经被扩展到 Windows 特定的功能(创建 Windows 服务)和一般有用的功能。例如,它可以在创建数据库期间设置“ root”用户密码。它还在数据目录中创建 my.ini 配置文件,并向其中添加最重要的参数(例如端口)。如果选择了“ Database instance” 特性,则 MariaDB Windows 安装程序将使用 mysql_install_db.exe。它废弃了过去使用的类似工具和脚本,如 mysqld.exe --install, mysql_install_db.pl, and mysql_secure_installation.pl。注意: 要创建 Windows 服务,mysql_install_db.exe 应该由具有完全管理员权限的用户运行(这意味着在使用 UAC 的系统上提高命令提示符)。例如,如果你正在 Windows 7上运行它,请确保你的命令提示符是通过 “Run as Administrator 以管理员身份运行” 选项启动的。案例:显示帮助消息和退出mysql_install_db.exe -?mysql_install_db.exe --datadir=C:\Users\likai1_wb\kkk\software\mariadb-10.6.5-data --service=MyDB --password=abc123 --port=3308 --allow-remote-root-access将在特定录中创建数据库,注册自动启动 Windows 服务“ MyDB”,并将根密码设置为“ abc123”。要从命令行启动服务,请执行sc start MyDB如果该命令启动不了 MyDB,查看是否登录身份。Removing Database Instances 删除数据库实例sc stop <servicename> sc delete <servicename> rmdir /s /q <path-to-datadir>开发 3308 端口本地访问可以直接使用 localhost,但是我在另一台电脑使用 root 进行访问。所以需要开启上面自定义的 3308 入站规则端口权限。鼠标右键点击“入站规则”,从弹出菜单中点击“新建规则”。在“要创建的规则类型”中,点选“端口”,下一步,选择“TCP”,点选“特定本地端口”后填入端口号。点击“下一步”,点选“允许连接”,再点“下一步”,根据用户的实际情况和需求勾选域、专用或共用等选项,最后为这个规则命名。MariaDB 入门登录 MariaDB(https://mariadb.com/kb/en/a-mariadb-primer/#logging-into-mariadb)mysql -u root --password=abc123 -h 10.1.212.135 -P 3308mysql (来自 MariaDB 10.4.6,也称为 mariadb) 是一个简单的 SQL shell (具有 GNU readline 功能)。它支持交互式和非交互式使用。交互式使用时,查询结果以 ascii 表格式显示。当非交互式地使用(例如,作为过滤器)时,结果以制表符分隔的格式显示。可以使用命令选项更改输出格式。因此可以写成这样也是可以的。mariadb -u root --password=abc123 -h 10.1.212.135 -P 3308如果你的登录是成功的,你应该看到类似这样的东西:MariaDB [test]>在这里输入所有 SQL 语句。稍后将详细介绍。现在,让我们看看提示符的组件: “ MariaDB”部分表示您已连接到 MariaDB 数据库服务器。方括号中的单词是默认数据库的名称。数据库建表CREATE DATABASE IF NOT EXISTS test; USE test; CREATE TABLE IF NOT EXISTS books ( BookID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, Title VARCHAR(100) NOT NULL, SeriesID INT, AuthorID INT); CREATE TABLE IF NOT EXISTS authors (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT); CREATE TABLE IF NOT EXISTS series (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT); INSERT INTO books (Title,SeriesID,AuthorID) VALUES('The Fellowship of the Ring',1,1), ('The Two Towers',1,1), ('The Return of the King',1,1), ('The Sum of All Men',2,2), ('Brotherhood of the Wolf',2,2), ('Wizardborn',2,2), ('The Hobbbit',0,1);SHOW TABLES; +----------------+ | Tables_in_test | +----------------+ | authors | | books | | series | +----------------+ 3 rows in set (0.00 sec)DESCRIBE books; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | BookID | int(11) | NO | PRI | NULL | auto_increment | | Title | varchar(100) | NO | | NULL | | | SeriesID | int(11) | YES | | NULL | | | AuthorID | int(11) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+SELECT * FROM books; +--------+----------------------------+----------+----------+ | BookID | Title | SeriesID | AuthorID | +--------+----------------------------+----------+----------+ | 1 | The Fellowship of the Ring | 1 | 1 | | 2 | The Two Towers | 1 | 1 | | 3 | The Return of the King | 1 | 1 | | 4 | The Sum of All Men | 2 | 2 | | 5 | Brotherhood of the Wolf | 2 | 2 | | 6 | Wizardborn | 2 | 2 | | 7 | The Hobbbit | 0 | 1 | +--------+----------------------------+----------+----------+ 7 rows in set (0.00 sec)插入数据INSERT INTO books (Title, SeriesID, AuthorID) VALUES ("Lair of Bones", 2, 2); Query OK, 1 row affected (0.00 sec)更新数据UPDATE books SET Title = "The Hobbit" WHERE BookID = 7; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0As you can see, using MariaDB isn't very difficult. You just have to understand the syntax of SQL since it doesn't allow for typing mistakes or things in the wrong order or other deviations.如你所见,使用 MariaDB 并不是很困难。您只需理解 SQL 的语法,因为它不允许键入错误或错误顺序的事情或其他偏差。参考A MariaDB Primer - MariaDB Knowledge Basehttps://mariadb.com/kb/en/a-mariadb-primer/
文章
SQL  ·  网络协议  ·  关系型数据库  ·  MySQL  ·  Shell  ·  Linux  ·  数据库  ·  数据安全/隐私保护  ·  开发者  ·  Windows
2022-05-17
MySQL 安装教程
Windows 上安装 MySQLMySQL 下载地址为: MySQL 下载 。 这里我们挑选 MySQL Community Server。拿到压缩包后我们将进行解压后配置启动。这里我将解压后的文件夹放在 C:\web\mysql-8.0.11 下。打开刚刚解压的文件夹 C:\web\mysql-8.0.11 ,在该文件夹下创建 my.ini 配置文件,编辑 my.ini 配置以下基本信息:[client] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] # 设置3306端口 port = 3306 # 设置mysql的安装目录 basedir=C:\\web\\mysql-8.0.11 # 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错 # datadir=C:\\web\\sqldata # 允许最大连接数 max_connections=20 # 服务端使用的字符集默认为8比特编码的latin1字符集 character-set-server=utf8 # 创建新表时将使用的默认存储引擎 default-storage-engine=INNODB接下来我们来启动下 MySQL 数据库:以管理员身份打开 cmd 命令行工具,切换目录:cd C:\web\mysql-8.0.11\bin初始化数据库:mysqld --initialize --console执行完成后,会输出 root 用户的初始默认密码,如:2018-04-20T02:35:05.464644Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: APWCY5ws&hjQ在这里,APWCY5ws&hjQ 就是初始密码,后续登录需要用到,你也可以在登录后修改密码。输入以下安装命令:mysqld install启动 mysql 服务:输入以下命令即可:net start mysql或者在 Windows 服务中手动选择 mysql 进行开启。停止服务net stop mysql卸载执行 msi 的卸载程序,手动删除 mysql 的 program File 和 program Data 目录。Linux 上 MySQL 的安装CentOS 7 安装 MySQLCentOS 7 系统下使用 yum 命令安装 MySQL,需要注意的是 CentOS 7 版本中 MySQL 数据库已从默认的程序列表中移除,所以在安装前我们需要先去官网下载 Yum 资源包,下载地址为:https://dev.mysql.com/downloads/repo/yum/wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm yum -y install mysql57-community-release-el7-10.noarch.rpm yum -y install mysql-community-server启动systemctl start mysqld.service查看 MySQL 运行状态:systemctl status mysqld 或者 systemctl status mysqld.service在启动 mysql 后,可以执行以下命令,查看 MySQL 初始密码。grep "password" /var/log/mysqld.log执行如下命令,修改 MySQL 默认密码。说明:新密码设置的时候如果设置的过于简单会报错,必须同时包含大小写英文字母、数字和特殊符号中的三类字符。ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassWord1.';ubuntu 安装mysqlapt-get install mysql-serverMac 下使用 brew 安装 MySQL$ brew install mysqlWe've installed your MySQL database without a root password. To secure it run: mysql_secure_installation MySQL is configured to only allow connections from localhost by default To connect run: mysql -uroot To have launchd start mysql now and restart at login: brew services start mysql Or, if you don't want/need a background service you can just run: mysql.server start后台开启服务mysql.server start停止 mysql 后台服务mysql.server stop重启服务brew services restart mysql使用套件进行安装小皮面板https://www.xp.cn/MAMPThe free web development solution with Apache, Nginx, PHP & MySQL。https://www.mamp.info/XAMPP是完全免费且易于安装的 Apache 发行版,其中包含 MariaDB、PHP 和 Perl。XAMPP 开放源码包的设置让安装和使用出奇容易。https://www.apachefriends.org/zh_cn/index.html新版本 MariaDB 已经取代了 MySQL,因此需要下载老版本的 XAMPP 或者直接切换成 MySQL 的衍生产品 MariaDB。docker 下安装 mysql 8.0.18https://www.jianshu.com/p/88de10c93f23参考
文章
关系型数据库  ·  MySQL  ·  Linux  ·  应用服务中间件  ·  Apache  ·  PHP  ·  数据库  ·  数据安全/隐私保护  ·  nginx  ·  Windows
2022-05-17
SpringCloud源码阅读0-SpringCloud必备知识
在开始源码阅读前,我觉得有必要先讲讲springcloud的体系。SpringCloud 是一系列微服务工具项目的集合。这个集合包含如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等工具。这些项目地址在:github.com/spring-clou…包含:Spring Cloud CommonsSpringCloud NetflixSpringCloud StreamSpringCloud Config .....本文着重讲讲两个项目:Spring Cloud commons此项目非常重要,因为他包含两个重要的子模块:1.Spring Cloud Context:为项目提供:引导上下文,加密,刷新范围和环境端点等功能。SpringCloud在构建上下文 (即ApplicationContext实例)时,采用了Spring父子容器的设计,会在 SpringBoot构建的容器(后面称之为应用容器)之上创建一父容器 Bootstrap Application Context 。2.Spring Cloud Commons: 看其名字也可以看出他是一个通用功能的项目,会被其他项目引入。主要对微服务中的服务注册与发现、负载均衡、熔断器等功能提供一个抽象层代码,这个抽象层与具体的实现无关。这样这些功能具体的实现上可以采用不同的技术去实现,并可以做到在使用时灵活的更换。列如:DiscoveryClient的使用,我们可以选择使用Spring Cloud Netflix Eureka,Spring Cloud Consul发现和Spring Cloud Zookeeper发现。当我们使用@EnableDiscoveryClient来引入DiscoveryClient时,具体引入哪种DiscoveryClient,会根据你具体引入哪个项目有关。如果我们用了Spring Cloud Netflix Eureka。那就会引入Spring Cloud Netflix Eureka的DiscoveryClient。当我们用用@EnableEurekaClient来引入DiscoveryClient,就是明确只能使用Spring Cloud Netflix Eureka的DiscoveryClient。这也是@EnableDiscoveryClient与@EnableEurekaClient的区别。由此我们能看出Spring Cloud Commons作为一个公共项目的目的。Spring Cloud NetflixNetflix公司开源一套分布式服务框架,Netflix OSS。项目地址github.com/NetflixSpring Cloud Netflix 项目对其进行了二次封装,使其更加适应springcloud体系。 Spring Cloud Netflix下包含了与Netflix OSS对应 子项目SpringCloud-Eureka -- Netflix EurekaSpringCloud-Ribbon -- Netflix RibbonSpringCloud-Hystrix -- Netflix Hystrix...当我们一想到springcloud ,就是Eureka,Ribbon。我认为这样是不对的,Eureka,Ribbon 只是作为Springcloud体系下Spring Cloud Netflix项目的子项目存在,他们只是微服务组件中的一种实现。因为我们常用Spring Cloud Netflix 项目下的这些实现,客观的认为Eureka,Ribbon 就是springcloud。因此在阅读源码前,理清这些关系springcloud,Spring Cloud Netflix ,Netflix OSS是非常有必要的。最重要的: 当我们阅读SpringCloud-Eureka,SpringCloud-Ribbon等源码时,参考Netflix OSS的wiki文档,对于我们理解他们很有帮助。springcloud文档地址:英文中文Netflix Eureka 英文地址英文文档Spring Cloud xxxspringcloud 集合下还有很多项目,项目地址在:github.com/spring-clou…总结:理解其中的一些关系后,后面开始对其中一些关键组件进行源码阅读。
文章
负载均衡  ·  监控  ·  前端开发  ·  Java  ·  对象存储  ·  数据安全/隐私保护  ·  微服务  ·  Spring  ·  容器
2022-05-17
node-24-token
1.前言前面session redis 讲的清晰,知道在哪里加密,解密就OK了so token只讲加密 解密做个了解更详细的可以查看阮一峰-JSON-Web-Token2.token加密不要忘记 installconst jwt = require('jsonwebtoken') // 加密内容 密钥 过期时间 var token = jwt.sign({ userName: "yzs" }, "小鸡炖蘑菇", { expiresIn:10 }) console.log(token)3.token解密// 解密 var timer = setInterval(function () { jwt.verify(token, "小鸡炖蘑菇", function (err,decode) { if (err) { console.log("密码错误:",err); } else { console.log(decode); clearInterval(timer); } }) },1000)4. token 起源基于服务器的验证我们都是知道HTTP协议是无状态的,这种无状态意味着程序需要验证每一次请求,从而辨别客户端的身份。2.在这之前,程序都是通过在服务端存储的登录信息来辨别请求的。这种方式一般都是通过存储Session来完成。5.基于服务器验证方式暴露的一些问题1.Seesion:每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。2.可扩展性:在服务端的内存中使用Seesion存储登录信息,伴随而来的是可扩展性问题。3.CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用Ajax抓取另一个域的资源,就可以会出现禁止请求的情况。4.CSRF(跨站请求伪造):用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。在这些问题中,可扩展行是最突出的。因此我们有必要去寻求一种更有行之有效的方法。token就运用而生了6. 基于Token的验证原理基于Token的身份验证是无状态的,我们不将用户信息存在服务器中。这种概念解决了在服务端存储信息时的许多问题。NoSession意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录。7. 基于Token的身份验证的过程如下:用户通过用户名和密码发送请求。服务器端程序验证。服务器端程序返回一个带签名的token 给客户端。客户端储存token,并且每次访问API都携带Token到服务器端的。服务端验证token,校验成功则返回请求数据,校验失败则返回错误码8.Tokens的优势1. 无状态、可扩展在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。tokens自己hold住了用户的验证信息。2.安全性请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。token是有时效的,一段时间之后用户需要重新验证。3. 可扩展性Tokens能够创建与其它程序共享权限的程序。4.多平台跨域9.项目中使用token总结使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:1.前端使用用户名跟密码请求首次登录2.后服务端收到请求,去验证用户名与密码是否正确3.验证成功后,服务端会根据用户id、用户名、定义好的秘钥、过期时间生成一个 Token,再把这个 Token 发送给前端4.前端收到 返回的Token ,把它存储起来,比如放在 Cookie 里或者 Local Storage 里export interface User { token: string; userInfo: UserInfo | any; companyInfo: CompanyInfo | any; resources?: string[]; } save(key: string, value: any, storageType ?: StorageType) { return this.storageService.put( { pool: key, key: 'chris-app', storageType: StorageType.localStorage }, value ); } this.storageService.save(CACHE_USER_KEY, user)5.前端每次路由跳转,判断 localStroage 有无 token ,没有则跳转到登录页。有则请求获取用户信息,改变登录状态;6.前端每次向服务端请求资源的时候需要在请求头里携带服务端签发的TokHttpInterceptor => headers = headers.set('token', this.authService.getToken());6.服务端收到请求,然后去验证前端请求里面带着的 Token。没有或者 token 过期,返回401。如果验证成功,就向前端返回请求的数据。7.前端得到 401 状态码,重定向到登录页面HttpInterceptor => 401: '用户登陆状态失效,请重新登陆。'
文章
存储  ·  前端开发  ·  NoSQL  ·  API  ·  Redis  ·  数据安全/隐私保护
2022-05-13
登陆页面实现保存帐号密码功能
通过Cookie实现"记住我"的功能1.登陆页面如下:每个字段对应的属性name如下表: 用户帐号name登陆密码password验证码checkNum记住我rememberMe 2.Action中的处理如下: 在用户第一次登陆后,进行Cookie进行处理登陆处理:/**登陆*/ public String login() throws Exception{ //处理验证码:判断验证码输入的是否正确 boolean flag=VerificationCodeUtil.isCheckNum(request); if(!flag){ this.addFieldError("checkNum", "验证码有误"); return "loginUI"; } User user=userService.findByLoginNameAndPassword(model.getName(),model.getPassword()); if(user==null){ addFieldError("login", "用户名或密码不正确"); return "loginUI"; }else{ ActionContext.getContext().getSession().put("user", user); //处理Cookie addCookie(model.getName(),model.getPassword(),response,request); return "toIndex"; } }Cookie处理:/**Cookie的实现 **/ private void addCookie(String name, String password,HttpServletResponse response, HttpServletRequest request) throws UnsupportedEncodingException { if(StringUtils.isNotBlank(name)&&StringUtils.isNotBlank(password)){ //创建Cookie Cookie nameCookie=new Cookie("name",URLEncoder.encode(name,"utf-8")); Cookie pswCookie=new Cookie("psw",password); //设置Cookie的父路径 nameCookie.setPath(request.getContextPath()+"/"); pswCookie.setPath(request.getContextPath()+"/"); //获取是否保存Cookie String rememberMe=request.getParameter("rememberMe"); if(rememberMe==null){//不保存Cookie nameCookie.setMaxAge(0); pswCookie.setMaxAge(0); }else{//保存Cookie的时间长度,单位为秒 nameCookie.setMaxAge(7*24*60*60); pswCookie.setMaxAge(7*24*60*60); } //加入Cookie到响应头 response.addCookie(nameCookie); response.addCookie(pswCookie); } }3.JSP页面的处理如下:在登陆的JSP页面中加入下面代码,以获得用户名和密码并自动填写:<% String name=""; String psw=""; String checked=""; Cookie[] cookies=request.getCookies(); if(cookies!=null&&cookies.length>0){ //遍历Cookie for(int i=0;i<cookies.length;i++){ Cookie cookie=cookies[i]; //此处类似与Map有name和value两个字段,name相等才赋值,并处理编码问题 if("name".equals(cookie.getName())){ name=URLDecoder.decode(cookie.getValue(),"utf-8"); //将"记住我"设置为勾选 checked="checked"; } if("psw".equals(cookie.getName())){ psw=cookie.getValue(); } } } %>最后对用户名,密码,记住我字段添加value即可:<TR> <TD class="td">用户帐号:</TD> <TD class="td"><input name="name" type="text" value="<%=name %>" id="name"/></TD> </TR> <TR> <TD class="td">登录密码:</TD> <TD class="td"><input name="password" type="password" value="<%=psw %>" id="password"></TD> </TR> <TR> <TD class="td">记住我:</TD> <TD class="td"><input name="rememberMe" type="checkbox" id="rememberMe" class="checkbox" <%=checked %>></TD> </TR>4.可能出现的问题如果出现设置了却没有自动填写用户名和密码,则可能是地址的问题:解决办法:1.进入Internet选项,点击浏览历史记录一栏的设置2.进入浏览记录设置后,点击查看文件3.在弹出的文件夹里找到Cookie文件,名字为你的项目名+“/”,格式如下图,这个文件一般在文件夹的最后面,将此文件复制到桌面,注:此文件是无法直接在该文件夹里打开的。4.如下图,第三行为保存项目工程的路径,此时在Action里的Cookie处理中,根据该地址设置对应的Cookie父路径即可,上文已经设置。
文章
Java  ·  数据安全/隐私保护
2022-05-17
自定义注解+拦截器实现权限控制
今天刚学习了通过自定义注解+拦截器实现权限控制,自己花了点时间整理,发到网站同网友交流分享。一、定义一个自定义注解类import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 自定义注解 * @author grace * */ @Retention(RetentionPolicy.RUNTIME) public @interface Limit{ String module(); //模块名称 String privilege(); //操作名称 }二、建好所需要的表#权限组表 CREATE TABLE `sys_role` ( `id` varchar(36), #编号 `remark` TEXT, #备注 `name` VARCHAR(100) DEFAULT NULL, #名称 PRIMARY KEY (`id`) )#操作表 CREATE TABLE sys_popedom ( popedomModule VARCHAR(30), #模块名称 popedomPrivilege VARCHAR(30), #操作名称 sort INTEGER(11), #排序 title VARCHAR(200), #提示 popedomName VARCHAR(200), #标题 remark TEXT, #说明 PRIMARY KEY(popedomModule,popedomPrivilege) )#操作权限表 CREATE TABLE sys_popedom_privilege ( roleId VARCHAR(36), #权限组编号 popedomModule VARCHAR(30), #模块名称 popedomPrivilege VARCHAR(30), #操作名称 PRIMARY KEY(roleId,popedomModule,popedomPrivilege) )解释下以上3个表的作用:1.权限组表:定义了一个权限,权限有id,name和remark。2.操作表:该表相当于是你这个项目里所有的权限。popedomModule代表一个大的功能模块,popedomPrivilege代表一个模块下的具体操作:常见的有增删改查,可参考下图理解。3.操作权限表:该表是权限组所对应的模块和操作。例子:如下图的roleId为8af0897545e4c91b0145e4cd385d0002,在权限组表中对应的是系统管理员权限组(见上上图),该权限组拥有的模块和操作名称在下图第二三列,可对应上图知道功能。说明:系统管理员权限组在当前系统中,只拥有下图所示的模块为city和code的所有操作权限,没有模块为company下的任何操作权限。通过将用户分配到不同的权限组,和设置权限组的拥有的模块和操作,就可以实现权限控制。三、定义上面三个表所对应的类和*.hbm.xml(如果需要)权限组表:/* * SysRole:权限组表 */ @SuppressWarnings("serial") public class SysRole implements java.io.Serializable { private String id; private String name; private String remark; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } }注:因为在操作表(sys_popedom)和权限操作表(sys_popedom_privilege)中都为联合主键。因此在这里,我对这两个类都使用:新建一个类用来存放联合主键。 操作表:/* * 操作表 */ @SuppressWarnings("serial") public class SysPopedom implements java.io.Serializable{ /* * CREATE TABLE sys_popedom ( popedomModule VARCHAR(30), #模块名称 popedomPrivilege VARCHAR(30), #操作名称 sort INTEGER(11), #排序 title VARCHAR(200), #提示 popedomName VARCHAR(200), #标题 remark TEXT, #说明 PRIMARY KEY(popedomModule,popedomPrivilege) ) */ private SysPopedomId id;//主键 OID private Integer sort; private String title; private String popedomName; private String remark; public SysPopedomId getId() { return id; } public void setId(SysPopedomId id) { this.id = id; } public Integer getSort() { return sort; } public void setSort(Integer sort) { this.sort = sort; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getPopedomName() { return popedomName; } public void setPopedomName(String popedomName) { this.popedomName = popedomName; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } }/** * 操作表中的联合主键类 * @author grace * */ @SuppressWarnings("serial") public class SysPopedomId implements java.io.Serializable { private String popedomModule; private String popedomPrivilege; public String getPopedomModule() { return popedomModule; } public void setPopedomModule(String popedomModule) { this.popedomModule = popedomModule; } public String getPopedomPrivilege() { return popedomPrivilege; } public void setPopedomPrivilege(String popedomPrivilege) { this.popedomPrivilege = popedomPrivilege; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((popedomModule == null) ? 0 : popedomModule.hashCode()); result = prime * result + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final SysPopedomId other = (SysPopedomId) obj; if (popedomModule == null) { if (other.popedomModule != null) return false; } else if (!popedomModule.equals(other.popedomModule)) return false; if (popedomPrivilege == null) { if (other.popedomPrivilege != null) return false; } else if (!popedomPrivilege.equals(other.popedomPrivilege)) return false; return true; } }操作权限表:/** * 操作权限表 * @author grace * */ @SuppressWarnings("serial") public class SysPopedomPrivilege implements java.io.Serializable { /* * CREATE TABLE sys_popedom_privilege * ( * roleId VARCHAR(36), #权限组编号 * popedomModule VARCHAR(30), #模块名称 * popedomPrivilege VARCHAR(30), #操作名称 * PRIMARY KEY(roleId,popedomModule,popedomPrivilege) * ) */ private SysPopedomPrivilegeId id; public SysPopedomPrivilegeId getId() { return id; } public void setId(SysPopedomPrivilegeId id) { this.id = id; } }/** * 操作权限表的联合主键类 * @author grace * */ @SuppressWarnings("serial") public class SysPopedomPrivilegeId implements java.io.Serializable { private String roleId; private String popedomModule; private String popedomPrivilege; public String getRoleId() { return roleId; } public void setRoleId(String roleId) { this.roleId = roleId; } public String getPopedomModule() { return popedomModule; } public void setPopedomModule(String popedomModule) { this.popedomModule = popedomModule; } public String getPopedomPrivilege() { return popedomPrivilege; } public void setPopedomPrivilege(String popedomPrivilege) { this.popedomPrivilege = popedomPrivilege; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((popedomModule == null) ? 0 : popedomModule.hashCode()); result = prime * result + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode()); result = prime * result + ((roleId == null) ? 0 : roleId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final SysPopedomPrivilegeId other = (SysPopedomPrivilegeId) obj; if (popedomModule == null) { if (other.popedomModule != null) return false; } else if (!popedomModule.equals(other.popedomModule)) return false; if (popedomPrivilege == null) { if (other.popedomPrivilege != null) return false; } else if (!popedomPrivilege.equals(other.popedomPrivilege)) return false; if (roleId == null) { if (other.roleId != null) return false; } else if (!roleId.equals(other.roleId)) return false; return true; } }如果需要*.hbm.xml则进行配置。四、写自定义拦截器import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; /** * 自定义拦截器 * @author grace * */ @SuppressWarnings("serial") public class LimitInterceptor extends MethodFilterInterceptor{ public String doIntercept(ActionInvocation invocation) throws Exception { //获取请求的action对象 Object action=invocation.getAction(); //获取请求的方法的名称 String methodName=invocation.getProxy().getMethod(); //获取action中的方法的封装类(action中的方法没有参数) Method method=action.getClass().getMethod(methodName, null); //获取request对象 HttpServletRequest request=ServletActionContext.getRequest(); //检查注解 boolean flag=isCheckLimit(request,method); if(!flag){ //没有权限,通过struts2转到事先定义好的页面 return "popmsg_popedom"; } //有权限,可以调用action中的方法 String returnvalue=invocation.invoke(); return returnvalue; } public boolean isCheckLimit(HttpServletRequest request, Method method) { if(method==null){ return false; } //获取当前的登陆用户 SysUser sysUser=SessionUtils.getSysUserFormSession(request); if(sysUser==null){ return false; } //如果用户的权限组为空 if(sysUser.getSysRole()==null){ return false; } //获取当前登陆用户的权限组id String roleId=sysUser.getSysRole().getId(); //处理注解 /* * @Limit(module="group",privilege="list") public String list(){ .... } */ //判断用户请求的method上面是否存在注解 boolean isAnnotationPresent= method.isAnnotationPresent(Limit.class); //不存在注解 if(!isAnnotationPresent){ return false; } //存在注解,拿到由Limit类写的注解 Limit limit=method.getAnnotation(Limit.class); //获取注解上的值 String module=limit.module(); //模块名称 String privilege=limit.privilege(); //操作名称 /** * 如果登陆用户的权限组id+注解上的@Limit(module="group",privilege="list") * * 在sys_popedom_privilege表中存在 flag=true; * * 在sys_popedom_privilege表中不存在 flag=false; */ boolean flag=false; //通过自己封装的方法拿到操作权限的业务层对象 ISysPopedomPrivilegeService sysPopedomPrivilegeService= (ISysPopedomPrivilegeService)ServiceProvinder.getService(ISysPopedomPrivilegeService.SERVICE_NAME); //查询sys_popedom_privilege表中的所有的数据 //因为后面用到二级缓存,因此这里直接查询出所有的操作权限,而不是通过登陆用户的权限组来查询 List<SysPopedomPrivilege> list=sysPopedomPrivilegeService.findAllSysPopedomPrivileges(); if(list!=null&&list.size()>0){ for(int i=0;i<list.size();i++){ SysPopedomPrivilege s=list.get(i); if(s!=null){ //判断登陆用户是否拥有该方法的权限:如果登陆用户的roleId和登陆用户访问的方法 //的注释中的module和privilege(例如@Limit(module="group",privilege="list")),这三个字段 //在sys_popedom_privilege表中有记录与之对应,则代表该用户拥有权限访问此方法 if(roleId.equals(s.getId().getRoleId())&&module.equals(s.getId().getPopedomModule()) &&privilege.equals(s.getId().getPopedomPrivilege())){ flag=true; break; } } } } return flag; } }五、在struts.xml中配置自定义拦截器和没有权限时访问的页面。<interceptors> <!-- 声明拦截器 --> <interceptor name="limitInterceptor" class="cn.grace.interceptor.LimitInterceptor"></interceptor> <interceptor-stack name="limitStack"> <interceptor-ref name="defaultStack" /> <interceptor-ref name="limitInterceptor"> <!-- 配置不被拦截的方法 --> <param name="excludeMethods">isLogin,logout,top,left</param> </interceptor-ref> </interceptor-stack> </interceptors> <!-- struts2运行时,执行的拦截器栈 --> <default-interceptor-ref name="limitStack" /> <global-results> <!-- 转发到没有权限的页面 --> <result name="popmsg_popedom">/WEB-INF/page/popmsg_popedom.jsp</result> </global-results>六、通过在Action的方法中进行注释,实现权限控制。import cn.grace.annotation.Limit; public class testUserAction { /** 用户添加页面 */ @Limit(module="user",privilege="add") public String add(){ return "add"; } /** 用户添加 **/ @Limit(module="user",privilege="save") public String save(){ return "save"; } /** 用户删除 **/ @Limit(module="user",privilege="delete") public String delete(){ return "delete"; } /** 用户修改页面 **/ @Limit(module="user",privilege="edit") public String edit() { return "edit"; } /** 用户修改 **/ @Limit(module="user",privilege="update") public String update() { return "update"; } /** 用户列表 (查询) */ @Limit(module="user",privilege="list") public String list() { return "list"; } }至此,权限控制实现完毕。七、整个权限控制的功能实现概要为:例子:3个不同权限的用户1.系统管理的权限id(roleId)为:8af0897545e4c91b0145e4cd385d0002;而在sys_popedom_privilege表中,roleId为:8af0897545e4c91b0145e4cd385d0002,拥有所有模块和操作,则系统管理员拥有所有模块的所有操作权限。2.部门经理的权限id(roleId)为:8af09d7845fe6ef90145fe70a0a80001;而在sys_popedom_privilege表中,roleId为:8af09d7845fe6ef90145fe70a0a80001,拥有部门模块的所有操作(9个),则部门经理拥有部门模块的所有9个操作权限,但没有其他(例如city和code模块)模块的操作权限。3.小明的权限id(roleId)为:8af0897545e4c91b0145e4cd65b30003;而在sys_popedom_privilege表中,roleId为:8af0897545e4c91b0145e4cd65b30003,仅拥有部门模块的部分操作(比部门经理比少了list和edit操作),则小明拥有部门模块下的部分操作权限。如下图,其中roleId为8af0897545e4c91b0145e4cd65b30003对应的模块和操作只有下图前7行。总结:自定义拦截器类会将当前登陆用户的roleId(上文中没有给出User表)和用户要访问的方法的@Limit注释中的module和privilege,共三个字段,与sys_popedom_privilege表中的三个字段进行比较,存在相应的记录,则表示用户有权限。否则,代表用户没有权限。​
文章
数据安全/隐私保护
2022-05-17
1 2 3 4 5 6 7 8 9
...
20
跳转至:
安全
1031 人关注 | 23272 讨论 | 50449 内容
+ 订阅
  • 【收集】【Linux】记录常用的操作指令 不定时更新
  • Python打包exe初体验----Pyinstaller
  • Google Pay支付遇到的问题(下)
查看更多 >
开发与运维
5177 人关注 | 125216 讨论 | 177855 内容
+ 订阅
  • 你知道String类为什么不能被继承吗?
  • 【收集】【Linux】记录常用的操作指令 不定时更新
  • Android ONE store支付
查看更多 >
数据库
248666 人关注 | 44341 讨论 | 53625 内容
+ 订阅
  • 【收集】【Linux】记录常用的操作指令 不定时更新
  • 事务的隔离级别和传播属性(下)
  • 事务的隔离级别和传播属性(上)
查看更多 >
云原生
229589 人关注 | 9466 讨论 | 25767 内容
+ 订阅
  • Spring注解(六):Bean的生命周期中自定义初始化和销毁方法的四种方式
  • Spring注解(五):容器注册组件的四种方式
  • Spring注解(四):@Conditional根据条件注册组件
查看更多 >
微服务
22755 人关注 | 9844 讨论 | 18621 内容
+ 订阅
  • 运行Spring项目报错 “Web server failed to start. Port 8080 was already in use.”(二)
  • Spring注解(六):Bean的生命周期中自定义初始化和销毁方法的四种方式
  • 运行Spring项目报错“Web server failed to start. Port 8080 was already in use.”(一)
查看更多 >