1.根据需求进行这几数据库,根据项目需要进行数据库的设计,设计需要的表结构,设计表设计出表中对用的数据。
/*
Navicat Premium Data Transfer
Source Server : localhost1
Source Server Type : MySQL
Source Server Version : 50719
Source Host : localhost:3306
Source Schema : liuboss
Target Server Type : MySQL
Target Server Version : 50719
File Encoding : 65001
Date: 09/07/2021 22:28:33
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_emp
-- ----------------------------
DROP TABLE IF EXISTS `t_emp`;
CREATE TABLE `t_emp` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`path` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`salary` double(10, 2) NULL DEFAULT NULL,
`age` int(3) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_emp
-- ----------------------------
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`username` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`realname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`sex` varchar(4) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`status` varchar(4) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`regsterTime` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_user
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 1;
设计项目目录结构
2.创建项目,搭建项目结构,引入相应的pom文件。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!--上传文件-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
运行项目项目搭建环境。
3.将静态资源文件拷贝到static文件夹中。
结果运行报错,原因可能是未加载到其中的静态文件,是因为之前项目的缓存文件,需要进行clean,问题解决。
重点:引入完资源时,运行加载依然是之前的项目,需要清理缓存。即可运行成功。
5.项目编码环节
1.实现动态验证码。
1.1 在regist.html中进行编码。
进行编码引入相关资源,找到页面的作用域将其引入。
<!--引入vue相关资源-->
<script src="/js/vue.js"></script>
<!--发送请求数据-->
<script src="/js/axios.min.js"></script>
<script>
var app = new Vue({
/*作用域*/
el: "#wrap",
/*作用域中所获取的数据*/
data: {
}
})
</script>
测试项目浏览器产看network是否将资源引入。
实现功能过程中不断进行项目的测试,在浏览器中打印日志,不断进行调试。
console.log("实现验证码功能!")
引入生成验证码工具类。放在utils工具文件包下面。
package com.liuboss.emp.utils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;
/**
*@描述 验证码生成
*/
public class VerifyCodeUtils{
//使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static Random random = new Random();
/**
* 使用系统默认字符源生成验证码
* @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 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 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);
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);
}
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 IOException {
//获取验证码
String s = generateVerifyCode(4);
//将验证码放入图片中
outputImage(260,60,new File("/Users/chenyannan/Desktop/安工资料/aa.jpg"),s);
System.out.println(s);
}
}
@getMapping与@postMapping
首先要了解一下@RequestMapping注解。
@RequestMapping用于映射url到控制器类的一个特定处理程序方法。可用于方法或者类上面。也就是可以通过url找到对应的方法。
@RequestMapping有8个属性。
value:指定请求的实际地址。
method:指定请求的method类型(GET,POST,PUT,DELETE)等。
consumes:指定处理请求的提交内容类型(Context-Type)。
produces:指定返回的内容类型,还可以设置返回值的字符编码。
params:指定request中必须包含某些参数值,才让该方法处理。
headers:指定request中必须包含某些指定的header值,才让该方法处理请求。
@getMapping与@postMapping是组合注解。
@getMapping = @requestMapping(method = RequestMethod.GET)。
@postMapping = @requestMapping(method = RequestMethod.POST)。
编码:实现验证码的生成,将base64位编码实现验证码的生成,并用留言器进行验证。
@RestController
@CrossOrigin //允许跨域
@RequestMapping("user")
public class UserController {
/*
* 生成验证码图片
* */
@GetMapping("getImage")
public String getImageCode(HttpServletRequest request) throws IOException {
//实用工具类生活生成验证码
String code = VerifyCodeUtils.generateVerifyCode(4);
//将验证码放入servletContext作用域
request.getServletContext().setAttribute("code",code);
//将图片转为base64
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
VerifyCodeUtils.outputImage(220,60,byteArrayOutputStream,code);
return "data:image/pang;base64,"+ Base64Utils.encodeToString(byteArrayOutputStream.toByteArray());
}
}
将后端的验证码在前段进行展示。
<script>
var app = new Vue({
/*作用域*/
el: "#wrap",
/*作用域中所获取的数据*/
data: {
},
/*引入vue生命周期中的函数,实现验证码功能*/
/*在页面加载之前完成此功能*/
created(){
/*console.log("实现验证码功能!");*/
//将验证码传递到前端 在线段进行展示
axios.get("http://localhost:8080/user/getImage").then(res=>{
console.log(res.data);
})
}
})
</script>
将后跳数据验证码和前台数据进行绑定
绑定验证码通过this传递给url绑定事件。
<script>
var app = new Vue({
/*作用域*/
el: "#wrap",
/*作用域中所获取的数据*/
data: {
url: ""
},
/*引入vue生命周期中的函数,实现验证码功能*/
/*在页面加载之前完成此功能*/
created(){
var _this = this;
/*console.log("实现验证码功能!");*/
//将验证码传递到前端 在线段进行展示
axios.get("http://localhost:8080/user/getImage").then(res=>{
console.log(res.data);
//通过图片将验证码赋值给图片,绑定url
_this.url =res.data;
});
}
})
</script>
前端查看
验证码显示成功
实现点击换一张验证码,实现点击换一张更新验证码。
在点击验证码重,为按钮绑定点击事件。
<td>
<img id="num" :src="url" />
<a href="javascript:;" @click="getImg">换一张</a>
</td>
浏览器进行测试,点击按钮验证码自动更新。
添加时间戳,浏览器默认路径相同时有缓存,加入时间戳,实现验证码自动更新。
//?time"+Math.random() 添加此注解是为了浏览器有缓存,当路径相同时验证码不会自动更新。
var _this = this;
//?time"+Math.random() 添加此注解是为了浏览器有缓存,当路径相同时验证码不会自动更新。
axios.get("http://localhost:8080/user/getImage?time"+Math.random()).then(res=>{
console.log(res.data);
//通过图片将验证码赋值给图片,绑定url
_this.url =res.data;
});
两个转换结构都需要加入时间戳。
有随机戳的时候浏览器将会人为每次浏览器发出的是不同请求。
当页面中出现相同代码,需要将其抽取成一个函数方法进行处理,放置代码的重复。
将相同之处抽取为一个函数进行调用
var _this = this;
//?time"+Math.random() 添加此注解是为了浏览器有缓存,当路径相同时验证码不会自动更新。
axios.get("http://localhost:8080/user/getImage?time"+Math.random()).then(res=>{
console.log(res.data);
//通过图片将验证码赋值给图片,绑定url
_this.url =res.data;
});
methods: {
getImg(){
this.getImg();
},
getSrc(){
this.getSrc();
}
},
/*引入vue生命周期中的函数,实现验证码功能*/
/*在页面加载之前完成此功能*/
created(){
var _this = this;
/*console.log("实现验证码功能!");*/
//将验证码传递到前端 在线段进行展示
axios.get("http://localhost:8080/user/getImage?time"+Math.random()).then(res=>{
console.log(res.data);
//通过图片将验证码赋值给图片,绑定url
_this.url =res.data;
});
用户验证码实现完成。
实现用户注册
当遇到报错标红提示时,检查应该是资源包导入错误。