文章目录
- SqlSessionFactoryUtils
- CheckCodeUtil
- java.util.UUID
- 文件上传下载
- java创建目录
- 多线程求和类型: java.util.concurrent.atomic.AtomicInteger [Stream流内可用]
- mybatisPlus提供的id工具类IdWorker
- Spring框架MD5加密工具类方法
- Spring框架 URL匹配工具类
- Spring框架 BeanUtils
- 阿里云短信发送
- 验证码生成
- 处理响应数据的中文乱码
- 后端原生方式给前端响应数据
- SpringMVC给前端直接响应字符串
- SpringMVC接收无POJO对应的JSON (Map接收)
- pom.xml 一些插件或者依赖,也也在这里吧
- JS
- 框架配置
SqlSessionFactoryUtils
package cn.whu.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionFactoryUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
//静态代码块会随着类的加载而自动执行,且只执行一次
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
CheckCodeUtil
生成随机图片验证码
package cn.whu.utils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.Random;
/**
* 生成验证码工具类
*/
public class CheckCodeUtil {
public static final String VERIFY_CODES = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static Random random = new Random();
/**
* 输出随机验证码图片流,并返回验证码值(一般传入输出流,响应response页面端,Web项目用的较多)
*
* @param w
* @param h
* @param os
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException {
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, os, verifyCode);
return verifyCode;
}
/**
* 使用系统默认字符源生成验证码
*
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize) {
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
*
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources) {
// 未设定展示源的字码,赋默认值大写字母+数字
if (sources == null || sources.length() == 0) {
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for (int i = 0; i < verifySize; i++) {
verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
}
return verifyCode.toString();
}
/**
* 生成随机验证码文件,并返回验证码值 (生成图片形式,用的较少)
*
* @param w
* @param h
* @param outputFile
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, outputFile, verifyCode);
return verifyCode;
}
/**
* 生成指定验证码图像文件
*
* @param w
* @param h
* @param outputFile
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, File outputFile, String code) throws IOException {
if (outputFile == null) {
return;
}
File dir = outputFile.getParentFile();
//文件不存在
if (!dir.exists()) {
//创建
dir.mkdirs();
}
try {
outputFile.createNewFile();
FileOutputStream fos = new FileOutputStream(outputFile);
outputImage(w, h, fos, code);
fos.close();
} catch (IOException e) {
throw e;
}
}
/**
* 输出指定验证码图片流
*
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 创建颜色集合,使用java.awt包下的类
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW};
float[] fractions = new float[colors.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions);
// 设置边框色
g2.setColor(Color.GRAY);
g2.fillRect(0, 0, w, h);
Color c = getRandColor(200, 250);
// 设置背景色
g2.setColor(c);
g2.fillRect(0, 2, w, h - 4);
// 绘制干扰线
Random random = new Random();
// 设置线条的颜色
g2.setColor(getRandColor(160, 200));
for (int i = 0; i < 20; i++) {
int x = random.nextInt(w - 1);
int y = random.nextInt(h - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
}
// 添加噪点
// 噪声率
float yawpRate = 0.05f;
int area = (int) (yawpRate * w * h);
for (int i = 0; i < area; i++) {
int x = random.nextInt(w);
int y = random.nextInt(h);
// 获取随机颜色
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
}
// 添加图片扭曲
shear(g2, w, h, c);
g2.setColor(getRandColor(100, 160));
int fontSize = h - 4;
Font font = new Font("Algerian", Font.ITALIC, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for (int i = 0; i < verifySize; i++) {
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
}
g2.dispose();
ImageIO.write(image, "jpg", os);
}
/**
* 随机颜色
*
* @param fc
* @param bc
* @return
*/
private static Color getRandColor(int fc, int bc) {
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
private static int getRandomIntColor() {
int[] rgb = getRandomRgb();
int color = 0;
for (int c : rgb) {
color = color << 8;
color = color | c;
}
return color;
}
private static int[] getRandomRgb() {
int[] rgb = new int[3];
for (int i = 0; i < 3; i++) {
rgb[i] = random.nextInt(255);
}
return rgb;
}
private static void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private static void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private static void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
public static void main(String[] args) throws Exception {
//生成验证码的图片位置
FileOutputStream fos = new FileOutputStream("E:\\data\\img\\code.jpg");
// checkCode 为最终验证码的数据
String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, fos, 4);
System.out.println(checkCode);
}
}
java.util.UUID
import java.util.UUID;
@Test
public void testUUID(){
int T=5;
while (T--> 0) {
String uuid = UUID.randomUUID().toString();
System.out.println(uuid);
}
}
文件上传下载
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="../../plugins/element-ui/index.css" />
<link rel="stylesheet" href="../../styles/common.css" />
<link rel="stylesheet" href="../../styles/page.css" />
</head>
<body>
<div class="addBrand-container" id="food-add-app">
<div class="container">
<el-upload class="avatar-uploader"
action="/common/upload"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeUpload"
ref="upload">
<img v-if="imageUrl" :src="imageUrl" class="avatar"></img>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="../../plugins/vue/vue.js"></script>
<!-- 引入组件库 -->
<script src="../../plugins/element-ui/index.js"></script>
<!-- 引入axios -->
<script src="../../plugins/axios/axios.min.js"></script>
<script src="../../js/index.js"></script>
<script>
new Vue({
el: '#food-add-app',
data() {
return {
imageUrl: ''
}
},
methods: {
handleAvatarSuccess (response, file, fileList) {
this.imageUrl = `/common/download?name=${response.data}`
},
beforeUpload (file) {
if(file){
const suffix = file.name.split('.')[1]
const size = file.size / 1024 / 1024 < 2
if(['png','jpeg','jpg'].indexOf(suffix) < 0){
this.$message.error('上传图片只支持 png、jpeg、jpg 格式!')
this.$refs.upload.clearFiles()
return false
}
if(!size){
this.$message.error('上传文件大小不能超过 2MB!')
return false
}
return file
}
}
}
})
</script>
</body>
</html>
application.yml
reggie:
path: E:\prodata\img\
后台
/**
* 文件上传下载
*/
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {
@Value("${reggie.path}") // 配置文件里读属性值 (文件保存路径写在配置文件里,方便项目上线后修改)
private String basePath;
/**
* 文件上传
*
* @param file
* @return
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file) {//前端name="file",这里也必须写file
// 刚传过来的file,是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除
log.info("文件上传,文件为: {}", file);
// 原始文件名
String originalFilename = file.getOriginalFilename();
String extend = originalFilename.substring(originalFilename.lastIndexOf("."));//后缀名
// 使用UUID重新生成文件名,防止文件重名覆盖
String fileName = UUID.randomUUID().toString() + extend;
// 创建一个目录对象 (new File(...)时,文件所在的目录必须存在 否则报错)
File dir = new File(basePath);
if (!dir.exists()) dir.mkdirs(); // 目录不存在则创建一个
try {
// 将临时文件转存到指定位置
file.transferTo(new File(basePath + fileName));
} catch (IOException e) {
throw new RuntimeException(e);
}
// 文件名传给前端,前端再发请求保存数据库 (文件名即可 路径不需要 因为服务器肯定知道文件保存在哪里)
return R.success(fileName);
}
@GetMapping("/download")
// 不需要返回值 而是以输出流的形式直接给出
public void download(HttpServletResponse response,String name) {
try {
// 1). 定义输入流,通过输入流读取文件内容
FileInputStream fis = new FileInputStream(basePath+name);
// 2). 通过response对象,获取到输出流
ServletOutputStream os = response.getOutputStream();//▲ 注意不是response.getWriter()
// 3). 通过response对象设置响应数据格式(image/jpeg)
response.setContentType("image/jpeg");
// 4). 通过输入流读取文件数据,然后通过上述的输出流写回浏览器
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
os.write(buffer, 0, len);
os.flush();
} // 代码提示好强大
// 5). 关闭资源
os.close();
fis.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
java创建目录
String basePath = "E:/data/img/"
File dir = new File(basePath);
if(!dir.exists()) dir.mkdirs(); // 目录不存在则创建一个
多线程求和类型: java.util.concurrent.atomic.AtomicInteger [Stream流内可用]
// 用AtomicInteger来计算总价Amount 他做了原子维护,是原子操作 即使多线程地算也不会算错
AtomicInteger amount = new AtomicInteger(0);
List<OrderDetail> orderDetails = carts.stream().map(cart -> {
BigDecimal number = new BigDecimal(cart.getNumber());
amount.addAndGet(cart.getAmount().multiply(number).intValue());
// 普通外面的变量无法在这里用 普通Integer求和也会出错
OrderDetail orderDetail = new OrderDetail();
//... 作别的逻辑
return orderDetail;
}).collect(Collectors.toList());
mybatisPlus提供的id工具类IdWorker
@Test
public void testIdWorker(){
long id = IdWorker.getId(); // 1647934642487431170
String uuid = IdWorker.get32UUID(); // 46518832c105cf7b9d8026d8e3473602
String idStr = IdWorker.getIdStr(); // 1647934642487431171
String millisecond = IdWorker.getMillisecond(); // 20230417200650575
String timeId = IdWorker.getTimeId(); // 202304172006505751647934642487431172
System.out.println(id);
System.out.println(uuid);
System.out.println(idStr);
System.out.println(millisecond);
System.out.println(timeId);
}
Spring框架MD5加密工具类方法
@SpringBootTest //这个类的包结构要和ReggieApplication启动类一样(或者子包) 否则@SpringBootTest注解无法被扫描到
public class APITest {
@Test
public void testDigestUtils(){
String password = "123456";
String encode = DigestUtils.md5DigestAsHex(password.getBytes());
System.out.println(encode);//e10adc3949ba59abbe56e057f20f883e
}
}
Spring框架 URL匹配工具类
/**
匹配0个或者1个或者多个 也即匹配任意多个
@Test
public void testAntPathMatcher(){
// 1. 先new出工具类 (因为人家提供的不是静态方法)
AntPathMatcher PATH_MATCHER = new AntPathMatcher();
// 2. 再进行匹配
// 匹配规则 pattern
String pattern = "front/**";
System.out.println("pattern:"+pattern);
System.out.println("------------------------------------------------------------");
String[] urls1 = {"front","front/index.html","front/page/index.html"};
for (String url : urls1) {
boolean b = PATH_MATCHER.match(pattern, url);
System.out.println(url+"\t\t\t"+b);
}
System.out.println("------------------------------------------------------------");
String[] urls2 = {"backend","backend/front","backend/font/index.html"};
for (String url : urls2) {
boolean b = PATH_MATCHER.match(pattern, url);
System.out.println(url+"\t\t\t"+b);
}
}
"/*"
必须匹配一个
@Test
public void testAntPathMatcher(){
// 1. 先new出工具类 (因为人家提供的不是静态方法)
AntPathMatcher PATH_MATCHER = new AntPathMatcher();
// 2. 再进行匹配
// 匹配规则 pattern
String pattern = "front/*";
System.out.println("pattern:"+pattern);
System.out.println("------------------------------------------------------------");
String[] urls1 = {"front","front/index.html","front/page/index.html"};
for (String url : urls1) {
boolean b = PATH_MATCHER.match(pattern, url);
System.out.println(url+"\t\t\t"+b);
}
System.out.println("------------------------------------------------------------");
String[] urls2 = {"backend","backend/front","backend/font/index.html"};
for (String url : urls2) {
boolean b = PATH_MATCHER.match(pattern, url);
System.out.println(url+"\t\t\t"+b);
}
}
Spring框架 BeanUtils
BeanUtils.copyProperties(), 两个类之间属性拷贝 (主要用于父类属性拷贝给增强过的子类)
import org.springframework.beans.BeanUtils;
@Data
class Student{
Integer age;
String name;
String gender;
}
@Test
public void testBeanUtils(){
Student stu = new Student();
stu.setName("天河");
stu.setAge(18);
stu.setGender("男");
Student stu1 = new Student();
BeanUtils.copyProperties(stu, stu1);
System.out.println(stu1);
Student stu2 = new Student();
BeanUtils.copyProperties(stu, stu2,"age");//忽略age属性(age属性不复制)
System.out.println(stu2);
Student stu3 = new Student();
BeanUtils.copyProperties(stu, stu3,"age","gender");//可变参数,可以忽略多个属性不复制
System.out.println(stu3);
}
阿里云短信发送
package cn.whu.reggie.utils;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
/**
* 短信发送工具类
*/
public class SMSUtils {
/**
* 发送短信
* @param signName 签名
* @param templateCode 模板
* @param phoneNumbers 手机号
* @param param 参数
*/
public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setSysRegionId("cn-hangzhou");
request.setPhoneNumbers(phoneNumbers);
request.setSignName(signName);
request.setTemplateCode(templateCode);
request.setTemplateParam("{\"code\":\""+param+"\"}");
try {
SendSmsResponse response = client.getAcsResponse(request);
System.out.println("短信发送成功");
}catch (ClientException e) {
e.printStackTrace();
}
}
}
验证码生成
package cn.whu.reggie.utils;
import java.util.Random;
/**
* 随机生成验证码工具类
*/
public class ValidateCodeUtils {
/**
* 随机生成验证码
* @param length 长度为4位或者6位
* @return
*/
public static Integer generateValidateCode(int length){
Integer code =null;
if(length == 4){
code = new Random().nextInt(9999);//生成随机数,最大为9999
if(code < 1000){
code = code + 1000;//保证随机数为4位数字
}
}else if(length == 6){
code = new Random().nextInt(999999);//生成随机数,最大为999999
if(code < 100000){
code = code + 100000;//保证随机数为6位数字
}
}else{
throw new RuntimeException("只能生成4位或6位数字验证码");
}
return code;
}
/**
* 随机生成指定长度字符串验证码
* @param length 长度
* @return
*/
public static String generateValidateCode4String(int length){
Random rdm = new Random();
String hash1 = Integer.toHexString(rdm.nextInt());
String capstr = hash1.substring(0, length);
return capstr;
}
}
处理响应数据的中文乱码
response.setContentType("text/json;charset=utf-8");
response.setContentType("text/html;charset=utf-8");
后端原生方式给前端响应数据
Controller 里用惯了 return 方式 给前端返回数据
原生的直接给前端响应数据方式反而忘了
response.getWriter().write("xx");
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));// 可以直接写json FastJson还是要懂点的
SpringMVC给前端直接响应字符串
直接return即可
@GetMapping("/sessionCode")
@ResponseBody
public String getSessionCode(HttpSession session) {
String code = (String) session.getAttribute("13112345678");
return "code: "+code;
}
SpringMVC接收无POJO对应的JSON (Map接收)
@PostMapping("/login")
public R<String> login(@RequestBody Map map){
log.info("验证码登陆: map接收任意格式的json, map={}",map);
}
pom.xml 一些插件或者依赖,也也在这里吧
tomcat7 插件
- 较为完整版本
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集 解决中文乱码-->
</configuration>
</plugin>
</plugins>
</build>
- 简略版:
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>80</port>
</configuration>
</plugin>
</plugins>
</build>
JS
浏览器控制台输出一下
console.log(data)
vue elementUI 弹窗
this.$message.success("添加成功");
this.$message.error("添加失败");
框架配置
mybatis打印sql
mybatis-config.xml核心配置文件中添加一行配置
<settings>
<!--打印sql-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>