简介:
详解:
秘钥:
在本地运行中加参数(在VM options中)
在项目部署的时候使用命令传入salt(盐)值
。打包时隐藏jasypt.encryptor.password,就需要打包时maven命令增加参数clean package -Djasypt.encryptor.password=Bt%XJ^n1j8mz 。不加参数的话打包就会报错。配置电脑本地环境变量APP_PASSWORD
--> 启动应用程序 --> 应用程序启动完成 --> 删除环境变量APP_PASSWORD。简介:
网页源码的编码探测
一般有两种方式,一种是通过分析网页源码中Meta信息,比如contentType,来取得编码,ICU4J就是基于第二种方式的类库。由IBM提供。
IntelliJ IDEA 的 HTTP Client:
纯编码操作
)RestfulToolkit辅助功能:
Live Template:
JSON Viewer:
Alibaba Java Coding Guidelines:
使用:在IDEA上边栏中点击Tools,再选中阿里编码规约。
简介:
其基本体系结构包括数据仓库、联机分析处理和数据挖掘三个部分。
最后将知识呈现给管理者,为管理者的决策过程提供支持。
BI与大数据的区别:
商业智能BI的工作原理:
简介:
SpringBoot之配置google kaptcha:
<dependency>
<groupId>com.google.code.kaptchagroupId>
<artifactId>kaptchaartifactId>
<version>2.3version>
dependency>
kaptcha提供了KaptchaServlet来处理验证码的生成并放入session
,但这方式在如今的分布式、前后端分离、集群的部署条件显然不适用。 <servlet>
<servlet-name>Kaptchaservlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServletservlet-class>
<init-param>
<param-name>kaptcha.borderparam-name>
<param-value>noparam-value>
init-param>
<init-param>
<param-name>kaptcha.textproducer.char.stringparam-name>
<param-value>02345689param-value>
init-param>
<init-param>
<param-name>kaptcha.background.clear.fromparam-name>
<param-value>whiteparam-value>
init-param>
<init-param>
<param-name>kaptcha.background.clear.toparam-name>
<param-value>whiteparam-value>
init-param>
<init-param>
<param-name>kaptcha.obscurificator.implparam-name>
<param-value>com.google.code.kaptcha.impl.WaterRippleparam-value>
init-param>
<init-param>
<param-name>kaptcha.noise.colorparam-name>
<param-value>255,96,0param-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>Kaptchaservlet-name>
<url-pattern>/images/captcha.jpgurl-pattern>
servlet-mapping>
Producer
,该接口目前只有一个默认实现类:com.google.code.kaptcha.impl.DefaultKaptchaTextProducer
,该忌口目前只有一个默认实现类:com.google.code.kaptcha.text.impl.DefaultTextCreator其中Producer是用来处理生成图片的,TextProducer是用来处理生成验证码问题的
。当然我们也可以去实现这个接口来实现自己的自定义的实现。kaptcha.border 是否有边框 默认为true 我们可以自己设置yes,no
kaptcha.border.color 边框颜色 默认为Color.BLACK
kaptcha.border.thickness 边框粗细度 默认为1
kaptcha.producer.impl 验证码生成器 默认为DefaultKaptcha
kaptcha.textproducer.impl 验证码文本生成器 默认为DefaultTextCreator
kaptcha.textproducer.char.string 验证码文本字符内容范围 默认为abcde2345678gfynmnpwx
kaptcha.textproducer.char.length 验证码文本字符长度 默认为5
kaptcha.textproducer.font.names 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
kaptcha.textproducer.font.size 验证码文本字符大小 默认为40
kaptcha.textproducer.font.color 验证码文本字符颜色 默认为Color.BLACK
kaptcha.textproducer.char.space 验证码文本字符间距 默认为2
kaptcha.noise.impl 验证码噪点生成对象 默认为DefaultNoise
kaptcha.noise.color 验证码噪点颜色 默认为Color.BLACK
kaptcha.obscurificator.impl 验证码样式引擎 默认为WaterRipple
kaptcha.word.impl 验证码文本字符渲染 默认为DefaultWordRenderer
kaptcha.background.impl 验证码背景生成器 默认为DefaultBackground
kaptcha.background.clear.from 验证码背景颜色渐进 默认为Color.LIGHT_GRAY
kaptcha.background.clear.to 验证码背景颜色渐进 默认为Color.WHITE
kaptcha.image.width 验证码图片宽度 默认为200
kaptcha.image.height 验证码图片高度 默认为50
//创建字符
String kaptchaText = kaptchaProducer.createText();
log.info("capText = {} ,kaptchaKey = {} ", kaptchaText, kaptchaKey);
//创建图片
BufferedImage bi = kaptchaProducer.createImage(kaptchaText);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bi, "jpeg", outputStream);
String base64Image = "data:image/jpeg;base64," + Base64.encodeBase64String(outputStream.toByteArray());
可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。
什么是数据脱敏?
public static void main(String[] args) {
String phone = "13123456789";
String phoneNumber = phone.substring(0, 3) + "****" + phone.substring(7, phone.length());
System.out.println("phone总长度:" + phone.length());
System.out.println("phone前3位:" + phone.substring(0, 3));
System.out.println("phone中4位:" + phone.substring(3, 7));
System.out.println("phone后4位:" + phone.substring(7, phone.length()));
System.out.println("phone中4*:" + phoneNumber);
}
二维码简述:
二维码其实就是一种编码技术,只是这种编码技术是用在图片上了,将给定的一些文字,数字转换为一张经过特定编码的图片,而解析二维码则相反,就是将一张经过编码的图片解析为数字或者文字。
我用的是谷歌提供的一个com.google.zxing.core包
二维码与解析二维码详解:
二维码生成:
字符在变成只有0和1组成的数字序列后,再进行一系列优化算法,就得到了最终的二进制编码。在最后这串编码中,一个0对应的就是一个白色小方块,一个1对应的就是一个黑色小方块,我们把这些小方块,按照8个一组,填进大方块里,这就是一个完整的,可以被手机相机识别的二维码图案了。二维码解析:
二维码扫描”实际上就是通过手机相机扫描『二维码图片』,将『二维码图片』中的字符串数据通过解码的方式解析出来。因此各家APP的扫一扫都会在扫出URL后在发送请求时加上对应的个人信息。
但有些例外:付款码,因此付款码不能轻易暴露。
微信扫一扫解析出登录地址,微信APP底层加上当前APP登录用户的信息,再发送请求到对应的URL。
这其中的请求参数是如何的,我们要到微信开放平台扫一扫功能中查看。
二维码代码使用:
package com.yc.qrcode;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import com.google.zxing.LuminanceSource;
public class BufferedImageLuminanceSource extends LuminanceSource {
private final BufferedImage image;
private final int left;
private final int top;
public BufferedImageLuminanceSource(BufferedImage image) {
this(image, 0, 0, image.getWidth(), image.getHeight());
}
public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
super(width, height);
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
if (left + width > sourceWidth || top + height > sourceHeight) {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
for (int y = top; y < top + height; y++) {
for (int x = left; x < left + width; x++) {
if ((image.getRGB(x, y) & 0xFF000000) == 0) {
image.setRGB(x, y, 0xFFFFFFFF); // = white
}
}
}
this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
this.image.getGraphics().drawImage(image, 0, 0, null);
this.left = left;
this.top = top;
}
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
image.getRaster().getDataElements(left, top + y, width, 1, row);
return row;
}
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
int area = width * height;
byte[] matrix = new byte[area];
image.getRaster().getDataElements(left, top, width, height, matrix);
return matrix;
}
public boolean isCropSupported() {
return true;
}
public LuminanceSource crop(int left, int top, int width, int height) {
return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
}
public boolean isRotateSupported() {
return true;
}
public LuminanceSource rotateCounterClockwise() {
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = rotatedImage.createGraphics();
g.drawImage(image, transform, null);
g.dispose();
int width = getWidth();
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
}
}
package com.yc.qrcode;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Random;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class QRCodeUtil {
private static final String CHARSET = "utf-8";
private static final String FORMAT_NAME = "JPG";
// 二维码尺寸
private static final int QRCODE_SIZE = 300;
// LOGO宽度
private static final int WIDTH = 60;
// LOGO高度
private static final int HEIGHT = 60;
private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
hints);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
if (imgPath == null || "".equals(imgPath)) {
return image;
}
// 插入图片
QRCodeUtil.insertImage(image, imgPath, needCompress);
return image;
}
private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
File file = new File(imgPath);
if (!file.exists()) {
System.err.println("" + imgPath + " 该文件不存在!");
return;
}
Image src = ImageIO.read(new File(imgPath));
int width = src.getWidth(null);
int height = src.getHeight(null);
if (needCompress) { // 压缩LOGO
if (width > WIDTH) {
width = WIDTH;
}
if (height > HEIGHT) {
height = HEIGHT;
}
Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(image, 0, 0, null); // 绘制缩小后的图
g.dispose();
src = image;
}
// 插入LOGO
Graphics2D graph = source.createGraphics();
int x = (QRCODE_SIZE - width) / 2;
int y = (QRCODE_SIZE - height) / 2;
graph.drawImage(src, x, y, width, height, null);
Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
}
public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
mkdirs(destPath);
// String file = new Random().nextInt(99999999)+".jpg";
// ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));
ImageIO.write(image, FORMAT_NAME, new File(destPath));
}
public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
return image;
}
public static void mkdirs(String destPath) {
File file = new File(destPath);
// 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
}
public static void encode(String content, String imgPath, String destPath) throws Exception {
QRCodeUtil.encode(content, imgPath, destPath, false);
}
// 被注释的方法
/*
* public static void encode(String content, String destPath, boolean
* needCompress) throws Exception { QRCodeUtil.encode(content, null, destPath,
* needCompress); }
*/
public static void encode(String content, String destPath) throws Exception {
QRCodeUtil.encode(content, null, destPath, false);
}
public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
ImageIO.write(image, FORMAT_NAME, output);
}
public static void encode(String content, OutputStream output) throws Exception {
QRCodeUtil.encode(content, null, output, false);
}
public static String decode(File file) throws Exception {
BufferedImage image;
image = ImageIO.read(file);
if (image == null) {
return null;
}
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result;
Hashtable hints = new Hashtable();
hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
result = new MultiFormatReader().decode(bitmap, hints);
String resultStr = result.getText();
return resultStr;
}
public static String decode(String path) throws Exception {
return QRCodeUtil.decode(new File(path));
}
}
邮件与Java:
JavaMail概述:
属性名 | 属性类型 | 说明 |
---|---|---|
mail.stmp.host | String | SMTP服务器地址,如smtp.sina.com.cn |
mail.stmp.port | int | SMTP服务器端口号,默认为25 |
mail.stmp.auth | boolean | SMTP服务器是否需要用户认证,默认为false |
mail.stmp.user | String | SMTP默认的登陆用户名 |
mail.stmp.from | String | 默认的邮件发送源地址 |
mail.stmp.socketFactory.class | String | socket工厂类类名,通过设置该属性可以覆盖提供者默认的实现,必须实现javax.net.SocketFactory接口 |
mail.stmp.socketFactory.port | int | 指定socket工厂类所用的端口号,如果没有规定,则使用默认的端口号 |
mail.smtp.socketFactory.fallback | boolean | 设置为true时,当使用指定的socket类创建socket失败后,将使用java.net.Socket创建socket,默认为true |
mail.stmp.timeout | int | I/O连接超时时间,单位为毫秒,默认为永不超时 |
JavaMail和Jakarta Mail:
Jakarta Mail的前生是JavaMail。JavaMail最后一个版本是于2018年8月发布,已经停止更新。新项目应该使用Jakarta Mail。
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>{version}</version>
</dependency>
基于SSM的spring发送邮件的实现:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>5.0.0.RELEASEversion>
dependency>
<dependency>
<groupId>com.sun.mailgroupId>
<artifactId>javax.mailartifactId>
<version>1.6.1version>
dependency>
#服务器主机名 smtp.xx.com
mail.smtp.host=smtp.163.com
[email protected]
#密码/客户端授权码
mail.smtp.password=XXXXXXXXX
#编码字符
mail.smtp.defaultEncoding=utf-8
#是否进行用户名密码校验
mail.smtp.auth=true
#设置超时时间
mail.smtp.timeout=20000
@Data
public class MailVo {
private String id;//邮件id
private String from;//邮件发送人
private String to;//邮件接收人
private String subject;//邮件主题
private String text;//邮件内容
private Date sentDate;//发送时间
private String cc; //抄送
private String bcc; //密送
private String status; //状态
private String error; //报错信息
@JsonIgnore
private MultipartFile[] multipartFiles;//邮件附件
}
Spring Boot笔记之邮件:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
spring:
mail:
# 163
host: smtp.163.com
port:
username: [email protected]
password: ************
protocol: smtp
default-encoding: UTF-8
properties:
mail.smtp.auth: true
mail.smtp.starttls.enable: true
mail.smtp.starttls.required: true
mail.smtp.socketFactory.port: 465
mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
mail.smtp.socketFactory.fallback: false
富文本与纯文本:
Markdown与富文本:
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。
富文本:富文本格式(Rich Text Format, 一般简称为RTF)
是由微软公司开发的跨平台文档格式。最大的特点是:所见即所得,你把格式调整成什么样子,就会直接显示出什么样的效果。这一点和words类似。Java与富文本:
Hello CSDN
,如果富文本不转文本,那么在显示的时候数据加载会很慢,这样不利于效率的提高。import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;
public class Html2Text extends HTMLEditorKit.ParserCallback {
private static Html2Text html2Text = new Html2Text();
StringBuffer s;
public Html2Text() {
}
public void parse(String str) throws IOException {
InputStream iin = new ByteArrayInputStream(str.getBytes());
Reader in = new InputStreamReader(iin);
s = new StringBuffer();
ParserDelegator delegator = new ParserDelegator();
// the third parameter is TRUE to ignore charset directive
delegator.parse(in, this, Boolean.TRUE);
iin.close();
in.close();
}
public void handleText(char[] text, int pos) {
s.append(text);
}
public String getText() {
return s.toString();
}
public static String getContent(String str) {
try {
html2Text.parse(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return html2Text.getText();
}
}
外部接口和内部接口:
Java调用第三方接口详解:
业务需求:
一般情况下都是后端提供接口,前端调用,解决需求,但是有的时候为了方便,复用别人的接口(网上的,公共的第三方接口(短信、天气等)),就出现了后端调用后端接口的情况。(类似JavaScript中的ajax一样获取数据,并对数据进行处理)开放平台:
开放平台(Open Platform) 在软件行业和网络中,开放平台是指软件系统通过公开其应用程序编程接口(API)或函数(function)来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源,而不需要更改该软件系统的源代码。在互联网时代,把网站的服务封装成一系列计算机易识别的数据接口开放出去,供第三方开发者使用,这种行为就叫做Open API,提供开放API的平台本身就被称为开放平台。需要下载SDK包并通过http调用,例如:阿里云OSS。链接:
AliyunOSS直接通过http调用。
简介:
Data URL简介:
这种方式中,img标记的src属性指定了一个远程服务器上的资源。当网页加载到浏览器中 时,浏览器会针对每个外部资源都向服务器发送一次拉取资源请求,占用网络资源。大多数的浏览器都有一个并发请求数不能超过4个的限制。这意味着,如果一个 网页里嵌入了过多的外部资源,这些请求会导致整个页面的加载延迟。为什么Data URL是个好东西?
埋点大概分成2种: