一.aop
概念:AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。
二.代码
一.日志实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Log {
private Integer id;
private String username;
private String className;
private String methodName;
private String args;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date beginTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date endTime;
private Integer exeTime;
}
二.Aop五种增强(代码中为环绕增强)
1.前置增强(Before Advice) 在目标方法执行之前执行的横切逻辑。可以用于执行一些预处理操作,如参数验证、权限检查等。
2.后置增强(After Advice) 在目标方法执行之后执行的横切逻辑。可以用于执行一些清理操作,如资源释放、日志记录等。
3.环绕增强(Around Advice) 在目标方法执行前后都可以执行的横切逻辑。环绕增强可以完全控制目标方法的执行过程,可以选择是否调用目标方法以及何时调用。
4.异常增强(After Throwing Advice) 在目标方法抛出异常时执行的横切逻辑。可以用于处理异常、发送通知等
5.最终增强(After finally) 它在目标方法执行结束后(无论是否发生异常)都会执行。最终增强通常用于资源清理或日志记录等必须执行的操作。
@Component
@Aspect
@Slf4j
public class LogAdvice {
@Qualifier("logServiceImpl")
@Autowired
private ILogService iLogService;
@Autowired
HttpSession session;
// @Around("execution(* com.woniu.guoqing.controller.*.*(..))")
@Around("@annotation(com.woniu.guoqing.ann.anno)")
//使用自定义注解的方式控制进行生效
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Date beginDate=new Date();
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getName();
Object[] target = joinPoint.getArgs();
log.info(className,methodName, Arrays.asList(target));
Object proceed = joinPoint.proceed();
Date endDate = new Date();
long exeTime = endDate.getTime() - beginDate.getTime();
String username=null;
Author author=(Author) session.getAttribute("author");
if (author!=null){
username=author.getUsername();
}
Log log = new Log();
log.setUsername(username);
log.setClassName(className);
log.setMethodName(methodName);
log.setArgs(Arrays.toString(target));
log.setBeginTime(beginDate);
log.setEndTime(endDate);
log.setExeTime((int) exeTime);
iLogService.insert(log);
return proceed;
}
}
三.自定义注解
@Target(ElementType.<em>METHOD</em>)
@Retention(RetentionPolicy.<em>RUNTIME</em>)
public @interface anno {
}
二.生成验证码
@Controller
public class ImageCodeController {
@RequestMapping("/imageCode")
public void imageCode(HttpSession httpSession, HttpServletResponse httpServletResponse) throws IOException {
String s = RandomUtil.randomNumbers(4);//生成随机的四位数
httpSession.setAttribute("yzm",s);
BufferedImage imageCode = ImageCodeUtils.createImageCode(200, 43, s);
ImageIO.write(imageCode,"png", httpServletResponse.getOutputStream());
}
}
/**
* 生成图片验证码
*/
public class ImageCodeUtils {
//根据传入的位数,生成随机字符
public static String getRandomStr(int length)
{
String s = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
Random random = new Random(System.currentTimeMillis());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int i1 = random.nextInt(s.length());
sb.append(s.charAt(i1));
}
return sb.toString();
}
public static void main(String[] args) throws IOException, InterruptedException {
for (int i = 0; i < 100; i++) {
Thread.sleep(10);
String randomStr = getRandomStr(4);
System.out.println(randomStr);
}
// //BuffereImage 图片缓冲流
// BufferedImage bufferedImage = createImageCode(100, 34, "ABCD");//生成图片的缓冲流
// //把缓冲流,写到某个输出流
// ImageIO.write(bufferedImage,"jpg",new FileOutputStream("/Users/edz/Desktop/11.jpg"));
}
public static BufferedImage createImageCode(int width, int height, String code) {
int codeSize = code.length();
BufferedImage image = new BufferedImage(width, height, 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, width, height);
Color c = getRandColor(200, 250);
g2.setColor(c);// 设置背景色
g2.fillRect(0, 2, width, height - 4);
// 绘制干扰线
Random random = new Random();
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
for (int i = 0; i < 20; i++) {
int x = random.nextInt(width - 1);
int y = random.nextInt(height - 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 * width * height);
for (int i = 0; i < area; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
}
shear(g2, width, height, c);// 使图片扭曲
g2.setColor(getRandColor(100, 160));
int fontSize = height - 4;
Font font = new Font("Algerian", Font.ITALIC, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for (int i = 0; i < codeSize; i++) {
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),
(width / codeSize) * i + fontSize / 2, height / 2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((width - 10) / codeSize) * i + 5, height / 2 + fontSize / 2 - 10);
}
g2.dispose();
return image;
}
private static Color getRandColor(int fc, int bc) {
Random random = ThreadLocalRandom.current();
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() {
Random random = ThreadLocalRandom.current();
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) {
Random random = ThreadLocalRandom.current();
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 = (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * phase) / 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) {
Random random = ThreadLocalRandom.current();
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 = (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * phase) / 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);
}
}
}
}
三、过滤器
@Configuration
public class SpringConfig implements WebMvcConfigurer {
@Value("${imglocation}")
String imglocation;
@Autowired
LoginAuthIntecepter loginAuthIntecepter;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/test/**")
.addResourceLocations("file:"+imglocation);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginAuthIntecepter)
.addPathPatterns("/**")//多级目录全部拦截
.excludePathPatterns("/author/login","/author/register","/author/loginPage",
"/author/registerPage","/imageCode","/bootstrap/**","/js/**","/static/favicon.ico");
}
}
//登录过滤器
@Component
public class LoginAuthIntecepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Author author = (Author) session.getAttribute("author");
if (author==null){
response.sendRedirect("/author/loginPage");
return false;
}else {
return true;
}
}
}
//自定义过滤器
@Component
public class MyIntecepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
//权限过滤器
@Component
public class Authrizalntecepter implements HandlerInterceptor {
@Qualifier("IUserRoleServiceImpl")
@Autowired
private IUserRoleService iUserRoleService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User) request.getSession().getAttribute("user");
Role roleByUserId = iUserRoleService.getRoleByUserId(user.getId());
if (handler instanceof HandlerMethod){
HandlerMethod handlerMethod=(HandlerMethod) handler;
PreAuthorize annotation = handlerMethod.getMethod().getAnnotation(PreAuthorize.class);
if (annotation!=null){
String[] values = annotation.value();
boolean b= Arrays.stream(values).anyMatch(value->value.equals(roleByUserId.getName()));
if (!b){
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.getWriter().write(JSON.toJSONString(new ResData(40001,"权限不足",null)));
return false;
}
}
}
return true;
}
}
四.上传图片
配置文件
imglocation: D:/test/
@Controller
public class UploadController {
@Value("${imglocation}")
String imglocation;
@RequestMapping("/uploadPage")
public String uploadPage(){
return "upload";
}
@RequestMapping("/upload")
@ResponseBody
public ResData upload(MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String extension = FilenameUtils.getExtension(originalFilename);
String s = UUID.randomUUID().toString().replace("-", "") + "." + extension;
file.getSize();
file.transferTo(new File( imglocation+ s));
return new ResData(200, "ok",s);
}
}
前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/js/jquery-3.5.1.js"></script>
<link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/js/axios.min.js"></script>
<script src="/js/vue.min-v2.5.16.js"></script>
</head>
<body>
<div id="app">
<input type="file" @change="upload">
<img :src="'/test/'+icon">
</div>
<script>
let app=new Vue({
el:"#app",
data:{
icon:""
},
methods:{
upload(env){
let file = env.target.files[0];
let formData = new FormData();
formData.append("file",file);
axios.post("/upload",formData,{
'Content-type': 'multipart/form-data'//要发送给后端的,有文件
}).then(response=>{
this.icon = response.data.data;
})}}
})
</script>
</body>
</html>
五.时间转换工具类
//(String和Date转换)
public class DateUtils {
public static Date stringToDate(String str,String pattern){
DateFormat df = new SimpleDateFormat(pattern);
Date birthdayDate = null;
try {
birthdayDate = df.parse(str);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return birthdayDate;
}
public static Date stringToDate(String str){
return stringToDate(str,"yyyy-MM-dd");
}
public static Date addOneDay(Date date){
date.setTime(date.getTime() + 24*60*60*1000-1);
return date;
}
}
六、SqlSession
//SqlSession 的主要作用包括:
//1. 提供对数据库的操作方法:SqlSession提供了一系列方法,用于执行数据库操作,如插入数据、更新数据、删除数据和查询数据等。
//2. 管理数据库连接:SqlSession 负责获取数据库连接,并在操作完成后释放连接,确保数据库连接的有效性和安全性。
//3. 实现事务管理:SqlSession 可以管理事务的提交、回滚和关闭,确保数据库操作的一致性和可靠性。
//4. 缓存管理:SqlSession中包含了一个缓存,用于缓存查询的结果,提高查询性能。在同一个 SqlSession 实例中执行相同的查询,可以直接从缓存中获取结果,而无需再次访问数据库。
public class SqlSessionUtil {
public static SqlSession sqlSession;
static{
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
//工厂建造者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//根据mybatis配置文档建造一个工厂
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
//工厂,生成一个SqlSession
sqlSession = sqlSessionFactory.openSession(true);
}
public static <T> T getMapper(Class<T> mapperClass){
return sqlSession.getMapper(mapperClass);
}
}
//mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.woniu.guoqing.mapper.LogMapper">
</mapper>
七、配置文件
//application.yml
server:
port: 80
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
mybatis:
type-aliases-package: com.woniu.guoqing.entity
mapper-locations: classpath:mapper/*Mapper.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
imglocation: D:/test/
八、一对多查询
<!-- newsMap映射,把下面sql查询出来的结果,映射成一条news信息-->
<resultMap id="newsMap" type="news">
<id column="ttt" property="id"></id>
<result column="title" property="title"></result>
<result column="content" property="content"></result>
<collection property="commentList" ofType="comment">
<id column="comment_id" property="id"></id>
<result column="id" property="newsId"></result>
<result column="comment_content" property="content"></result>
<!-- 放在collection里面,select="com.woniu.mapper.CommentMapper.query"colun="id>-->
</collection>
</resultMap>
<select id="selectById1" parameterType="integer" resultMap="newsMap">
select news.id,news.title,news.content,comment.id comment_id,comment.content comment_content from news
left join comment
on news.id=comment.news_id
where news.id=#{id}
</select>
九、全局异常类
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
@ResponseBody
public ResData nullPointExceptionHandler() {
return new ResData(10001, "空指针异常", null);
}
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public ResData ArithmeticException() {
return new ResData(10002, "数字异常", null);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public ResData Exception() {
return new ResData(10003, "系统繁忙", null);
}
}
十、手机验证码登录
/**
* new SmsThread(ShortMes)
* 因为这个线程是发短信的线程,所以需要用户给一个手机号,验证码才能发...,所以通过构造函数传一个
*/
public class SmsThread implements Runnable{
private ShortMes shortMes;
public SmsThread() {
}
public SmsThread(ShortMes shortMes) {
this.shortMes = shortMes;
}
/**
* 子类不能抛出父类没有的异常
*
*/
@Override
public void run() {
try {
SMSUtils.send(shortMes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//工具类(通过阿里云获取)
public class SMSUtils {
public static void send(ShortMes shortMes) throws IOException {
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tKSK6vEeTHY5Mzvd9yN", "TPGxhbOWtmeQxwAlrMP97s8PoROreR");
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
request.putQueryParameter("RegionId", "cn-hangzhou");
request.putQueryParameter("PhoneNumbers", shortMes.getAccount());//往什么手机号发
request.putQueryParameter("SignName", "MT4账号");
request.putQueryParameter("TemplateCode", "SMS_157449478");
request.putQueryParameter("TemplateParam", JSON.toJSONString(shortMes));//发送的内容
try {
CommonResponse response = client.getCommonResponse(request);
System.out.println(response.getData());
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
ShortMes shortMes = new ShortMes("手机号码","手机号码","1111");
send(shortMes);
}
}
@RequestMapping("/loginSms")
@ResponseBody
@anno
public ResData loginSms(@RequestBody User user, HttpSession httpSession) {
if (StrUtil.isEmpty(user.getTel()) || StrUtil.isEmpty(user.getYzm())) {
return new ResData(10001, "必填项为空", null);
}
String s = redisTemplate.opsForValue().get(user.getTel());
if (user.getYzm().equals(s)){
return new ResData(10002, "验证码错误", null);
}
redisTemplate.delete(user.getTel());
User user1 = iUserService.queryByTel(user.getTel());
httpSession.setAttribute("user", user1);
return new ResData(200, "ok", user1.getUsername());
}
//前端页面
loginsms(){
let owner = {};
owner.tel = this.tel;
owner.yzm = this.yzm;
axios.post("/user/loginSms",owner)
.then(response=>{
let rs = response.data;
if (rs.code == 200) {
localStorage
.setItem("username",this.username);
window.location = "/index.html";
} else {
this.msg = rs.msg;
}
},error=>{
})
}