1、day01-AOP 面向切面(儿)编程:面向程序的横截面(儿)编程,将软件横向切开,在原有软件不变的情况下扩展横向的功能。 AOP:
如何没有AOP将会是这样的:
你好,世界 AOP的演示案例: 步骤:
- 导入包:
-
aspectjweaver:(汉)编辑切面;
aspectjtools:(汉)切面工具
org.springframework spring-aop3.2.8.RELEASE org.aspectj aspectjweaver1.8.0 org.aspectj aspectjtools1.8.0 -
开发了AOP Bean组件
@Component //Component:(汉)组成构成;将DemoAspect交给Spring管理 @Aspect //声明当前Bean组件是一个切面组件 public class DemoAspect { @Before("bean(userService)") public void test(){ System.out.println("Hello World!"); } } -
配置:
通知 用于声明AOP方法在目标业务方法执行时机。 常用的有5种通知:
@Before //(汉)在**方法之前;的全部方法之前执行。 @After //(汉)在**方法之后;的全部方法之后执行。 @AfterThrowing //(汉)在**方法之后后抛;在目标方法有异常情况下抛出。 @AfterReturning //(汉)在**方法之后回归;目标方法正常执行之后执行。 @Around //(汉)周围,环绕
执行原理如下:
@Before 在**之前
在目标方法之前执行,案例:
@Before("bean(userService)")
public void test(){
System.out.println("Hello World!");
}
@After 在**之后
在目标方法执行之后执行,无论目标业务方法是否出现异常@After修饰的方法都会执行:
@After("bean(userService)")
public void test2(){
System.out.println("Hello @After!");
}
@AfterReturning接口
在目标方法正常执行之后,如果没有异常发生,则执行@AfterReturning接口修饰的方法:
@AfterReturning("bean(userService)")
public void test3(){
System.out.println("Hello @AfterReturning");
}
@AfterThrowing
在目标方法执行出现异常以后会执行@AfterThrowing修饰的方法。
@AfterThrowing("bean(userService)")
public void test4(){
System.out.println("Hello @AfterThrowing");
}
@Around 通知; (汉)周围;
这个是一个万能通知,可以替代其他几个通知,但是使用繁琐:
案例:
@Around("bean(userService)")
public Object test5(ProceedingJoinPoint jp)
throws Throwable{
//Proceeding 进行,处理
//Join 连接
//Point 点
// 处理过程的连接点
System.out.println("Around Before");
//jp.proceed() 调用了目标业务方法,其返回值
//就是业务方法返回的业务处理结果
Object obj = jp.proceed();
//jp 对象中包含被调用目标方法的全部信息
//其中 getSignature 返回方法的签名,包括:
//方法和方法的参数类型列表
Signature method= jp.getSignature();
System.out.println(method);
System.out.println("Around After:"+obj);
return obj;
}
切入点表达式切入点 切入点用于声明对那些类,对象,方法进行AOP切入 豆组件切入点 语法:
@Before("bean(userService)") //切入到userService的全部方法
@Before("bean(userService) || bean(dictService)")
案例:
//@Before("bean(userService) || bean(dictService)")
public void test(){
System.out.println("Point Cut Test!");
}
//@Before("bean(*Service)")
public void test1(){
System.out.println("Point Cut Test1!");
}
类切入点
按照具体的类名,切到类的全部方法
语法:
//切入到类 UserServiceImpl 中声明的全部的方法
@Before("within(cn.tedu.store.service.UserServiceImpl)")
@Before("within(cn.tedu.store.service.*ServiceImpl)")
@Before("within(cn.tedu.store..*Impl)")
案例:
@Before("within(cn.tedu.store.service.UserServiceImpl)")
public void test2(){
System.out.println("Point Cut Test2!");
}
@Before("within(cn.tedu.store.service.*ServiceImpl)")
public void test3(){
System.out.println("Point Cut Test3!");
}
方法切入点
语法:
//execution 执行
@Before("execution(修饰词 类名.方法名(参数类型))")
@Before("execution(* cn.tedu.store.service.UserService.login(..))")
@Before("execution(* cn.tedu.store.service.*Service.get*(..))")
@Before("execution(* cn.tedu.store..*Service.get*(..))")
案例:
@Before("execution(* cn.tedu.store.service.*Service.login(..))")
public void test4(){
System.out.println("Point Cut Test4!");
}
测试业务层的所有方法的性能 方案:
@Component
@Aspect
public class TestAspect {
@Around("bean(*Service)")
public Object test(ProceedingJoinPoint jp)
throws Throwable{
try {
long t1 = System.currentTimeMillis();
Object val=jp.proceed();
long t2 = System.currentTimeMillis();
Signature m = jp.getSignature();
System.out.println((t2-t1)+":"+m);
return val;
} catch (Throwable e) {
//继续抛出业务异常
throw e;
}
}
}
AOP的工作原理 Spting底层是AspectJ再底层利用了Java的反射和动态代理。其中反射用于解析注解,动态代理用于生成代理对象。 Spring AOP的底层代理方式有两种,一种是基于Java动态代理对象,一种是基于CGlib的动态代理。当前代理对象有接口时候优先使用JAVA动态代理,如果被代理对象没有接口时候,会自动使用CGLIB。推荐使用JAVA动态代理。
2、day02-HTTP文件的上载和下载
@RequestMapping(value="code.do",produces="image/png")
@ResponseBody
public byte[] code() throws IOException {
String code = getCode(4);
byte[]png =createPng(code);
return png;
}
private byte[] createPng(String code) throws IOException {
//1.利用BufferedImage 创建img对象;BufferedImage 子类描述具有可访问图像数据缓冲区的 Image
BufferedImage img = new BufferedImage(100, 40,BufferedImage.TYPE_3BYTE_BGR);
//设置坐标为(50,20)的灯亮
img.setRGB(50, 20, 0xffff00);
//graphics:(汉)绘制学
Graphics2D g =img.createGraphics();
//生成随机色
Random random = new Random ();
Color c = new Color(random.nextInt(0xffffff));
g.setColor(c);
//填充矩形
g.fillRect(0, 0, 100, 40);
//绘制300个随机点
for(int i=0;i<300;i++) {
int x = random.nextInt(100);
int y = random.nextInt(40);
int rgb = random.nextInt(0xffffff);
img.setRGB(x, y, rgb);
}
//设置平滑抗锯齿绘制
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//设置字体大小
g.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,30));
//设置字体随机色
g.setColor(new Color(random.nextInt(0xffffff)));
//画字
g.drawString(code, 10, 30);
//在字体上乱画线
for(int i=0;i<10;i++) {
int x1=random.nextInt(100);
int y1=random.nextInt(40);
int x2=random.nextInt(100);
int y2=random.nextInt(40);
g.drawLine(x1, y1, x2, y2);
}
//2.利用imageIO将img编码png
ByteArrayOutputStream out = new ByteArrayOutputStream();//酱油瓶子
ImageIO.write(img, "png", out);//将酱油装进瓶子
out.close();
byte[]bytes = out.toByteArray();//将酱油倒出
return bytes;
}
public byte[] createPng2() throws IOException {
//缓冲图片
BufferedImage img = new BufferedImage (100,40,BufferedImage.TYPE_3BYTE_BGR);
//把其中的图片的灯打开
for(int x = 0 ;x<100;x++) {
for(int y=0;y<40;y++) {
img.setRGB(x, y, 0xff0000);
}
}
//容器
ByteArrayOutputStream out = new ByteArrayOutputStream();
//将缓冲图片放进瓶子,并转换成png格式
ImageIO.write(img, "png", out);
out.close();
//将转好格式的图片写出
byte [] bytes = out.toByteArray();
return bytes;
}
private static String chs = "3456789abcdefghigkmnopqrstwxy";
public String getCode(int nub) {
char[] code =new char[nub];
Random random = new Random();
for(int i=0;i
HTTP文件的上载和下载
HTTP下载
HTTP协议下载关键点:
-
设置响应状态码为200
-
设置响应头Content-Type
-
设置响应头内容长度
-
在响应正文中发送下载字节数据,数据内容必须与内容类型一致,数据长度必须与内容长度一致。
原理:
Spring MVC下载
用SpringMVC对资源下载做了封装:
-
利用@RequestMapping(生产= “图像/ PNG”)设置的内容类型
-
利用@ResponseBody和控制器方法byte []类型的返回值填充响应Body,并且自动设置Content-Length
生成验证码图片案例:
@RequestMapping(value="code.do",
produces="image/png")
@ResponseBody
public byte[] code(HttpSession session)
throws IOException{
String code = genCode(4);
session.setAttribute("code", code);
byte[] png = createPng(code);
return png;
}
private byte[] createPng(String code) throws IOException{
//1. 利用BufferedImage 创建 img 对象
BufferedImage img=new BufferedImage
(100, 40, BufferedImage.TYPE_3BYTE_BGR);
img.setRGB(50, 20, 0xffffff);
Graphics2D g=img.createGraphics();
Random random = new Random();
//生成随机颜色:
Color c=new Color(random.nextInt(0xffffff));
//填充图像的背景
g.setColor(c);
g.fillRect(0, 0, 100, 40);
//绘制500个随机点
for(int i=0; i<500; i++){
int x=random.nextInt(100);
int y=random.nextInt(40);
int rgb=random.nextInt(0xffffff);
img.setRGB(x, y, rgb);
}
//设置平滑抗锯齿绘制
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//设置字体大小
g.setFont(new Font(Font.SANS_SERIF,
Font.PLAIN, 30));
g.setColor(new Color(
random.nextInt(0xffffff)));
g.drawString(code, 10, 30);
//随机绘制10条线段
for(int i=0; i<10; i++){
int x1=random.nextInt(100);
int y1=random.nextInt(40);
int x2=random.nextInt(100);
int y2=random.nextInt(40);
g.drawLine(x1, y1, x2, y2);
}
//2. 利用ImageIO将 img 编码为png
ByteArrayOutputStream out=
new ByteArrayOutputStream();
ImageIO.write(img, "png", out);
out.close();
byte[] bytes=out.toByteArray();
return bytes;
}
private static String chs=
"345678abcdefhjkmnpqrstuvwxyABCDEFGHJL";
private String genCode(int len){
char[] code=new char[len];
Random random = new Random();
for(int i=0; i
检验验证码原理:
步骤:
-
login.jsp的中添加IMG标签显示图片:
-
更新login.css显示位置
#cover .txt{
float: left;
overflow: hidden;
width: 253px;
padding: 10px;
}
-
发起AJAX请求验证
$("#code").blur(function(){
var data = $("#code").val();
console.log(data);
if (data == null || data == "") {
$("#showResult").text("验证码不能为空!");
$("#showResult").css("color","red");
return false;
}
$.ajax({
"type":"POST",
"url":"checkCode.do",
"data":"code="+data,
"beforeSend":function(XMLHttpRequest){
$("#showResult").text("正在查询...");
$("#showResult").css("color", "green");
},
"success":function(obj) {
var color = obj.state == 1
? "green" : "red";
$("#showResult").css("color", color);
$("#showResult").text(obj.message);
},
"error":function() {
//错误处理
}
});
});
-
添加更新点击更新图片的方法
//点击验证码图片时候更新图片$(“#code_image”)。click(function(){var img = this; console.log(img); //添加请求参数的目的避免浏览器的缓存img.src =“code.do?”+ new Date()。getTime();});
-
添加检验验证码控制器方法
@RequestMapping("checkCode.do")
@ResponseBody
public ResponseResult checkCode(
String code,
HttpSession session){
ResponseResult rr=
new ResponseResult();
String c = (String)session.getAttribute("code");
if(c !=null && c.equalsIgnoreCase(code)){
rr.setState(ResponseResult.STATE_OK);
rr.setMessage("验证码检查通过");
}else{
rr.setState(ResponseResult.STATE_ERROR);
rr.setMessage("验证码错误");
}
return rr;
}
-
放过验证请求spring-mvc.xml:
-
测试....
自动下载图片功能
HTTP协议中如果了下载属性头内容处置,设置这个响应头,就可以实现下载保存到文件中:
步骤:
-
编写控制器方法
@RequestMapping(value = "/downloadImage.do", produces="image/png")
@ResponseBody
public byte[] downloadImage(HttpServletResponse response) throws IOException { System.out.println("下载图片");
response.setHeader("Content-Disposition",
"attachment;filename="ok.png"");
byte [] bytes = createPng("OK");
return bytes;
}
private byte[] createPng(String code) throws IOException {
//1.利用BufferedImage 创建img对象;BufferedImage 子类描述具有可访问图像数据缓冲区的 Image
BufferedImage img = new BufferedImage(100, 40,
BufferedImage.TYPE_3BYTE_BGR);
//设置坐标为(50,20)的灯亮
img.setRGB(50, 20, 0xffff00);
//graphics:(汉)绘制学
Graphics2D g =img.createGraphics();
//生成随机色
Random random = new Random ();
Color c = new Color(random.nextInt(0xffffff));
//设置背景色
g.setColor(c);
//fillRect:(汉)填充矩形;
g.fillRect(0, 0, 100, 40);
//绘制300个随机点
for(int i=0;i<100;i++) {
int x = random.nextInt(100);
int y = random.nextInt(40);
int rgb = random.nextInt(0xffffff);
img.setRGB(x, y, rgb);
}
//设置平滑抗锯齿绘制;RenderingHint打底示意
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//设置字体大小 sans serif:字体 plain:平滑的
g.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,30));
//设置字体随机色
g.setColor(new Color(random.nextInt(0xffffff)));
//画字; 从字符的位置(10,30)开始画字符
g.drawString(code,10, 30);
//在字体上乱画线
for(int i=0;i<10;i++) {
int x1=random.nextInt(100);
int y1=random.nextInt(40);
int x2=random.nextInt(100);
int y2=random.nextInt(40);
g.drawLine(x1, y1, x2, y2);
}
//2.利用imageIO将img编码png
ByteArrayOutputStream out = new ByteArrayOutputStream();//酱油瓶子
ImageIO.write(img, "png", out);//将酱油装进瓶子
out.close();
byte[]bytes = out.toByteArray();//将酱油倒出
return bytes;
}
-
客户端下载连接:
downloadImage.do">下载
-
测试...
下载Excel中
与下载PNG图片的原理一样,只是的ContentType的值不同:
1、导入POI API
org.apache.poi
poi-ooxml
3.16
2、编写控制器方法
@RequestMapping(value = "/downloadExcel.do",
produces="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
@ResponseBody
public byte[] downloadExcel(HttpServletResponse response) throws IOException {
System.out.println("下载Excel表");
response.setHeader("Content-Disposition", "attachment; filename="ok.xlsx"");
byte [] bytes = createExcel();
return bytes;
}
@SuppressWarnings("resource")
private byte[] createExcel() throws IOException{
//创建工作薄
XSSFWorkbook workbook = new XSSFWorkbook();
//在工作表中添加工作表;Sheet:(汉)片
XSSFSheet sheet1 = workbook.createSheet("花名册");
//在工作表中添加两行 Row:(汉)行
XSSFRow head = sheet1.createRow(0);
XSSFRow row = sheet1.createRow(1);
//第一行作为表头;createCell(汉)创建一个小格子
XSSFCell c0 = head.createCell(0);
//将创建的一个格子添加“编号”属性
c0.setCellValue("编号");
head.createCell(1).setCellValue("姓名");
head.createCell(2).setCellValue("年龄");
row.createCell(0).setCellValue(1);
row.createCell(1).setCellValue("范传奇");
row.createCell(2).setCellValue(34);
//将Excel对象保存为bytes
ByteArrayOutputStream out = new ByteArrayOutputStream();
//将这个工作薄写入到字节数组输出流里
workbook.write(out);
out.close();
byte [] bytes = out.toByteArray();
return bytes;
}
3、添加客户端链接
Excel
4、测试
上载文件
HTTP上载是基于RFC 1867标准,Spring MVC利用Apache commons fileupload组件支持了这个标准,这样利用Spring MVC提供的API可以轻松的获得上载文件:
参考Spring 3.2 手册: 17.10 Spring's multipart (file upload) support
表单上载
实现上载步骤:
-
导入 commons fileupload 上载组件
commons-fileupload
commons-fileupload
1.3.3
-
在spring-MVC中配置Spring 上载解析器:
-
编写表单 web/upload.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
文件上载
文件上载
编写控制器方法显示表单
@RequestMapping("uploadForm.do")
public String uploadForm(){
return "upload";
}
编写控制器处理上载请求
@RequestMapping(value="upload.do",
method=RequestMethod.POST)
@ResponseBody
public ResponseResult upload(
@RequestParam("userfile1") MultipartFile image,
@RequestParam("username") String username,
HttpServletRequest request)
throws IOException {
//打桩输出上载结果
System.out.println(username);
System.out.println(image);
//获取上载文件信息
System.out.println(image.getContentType());
System.out.println(image.getName());
System.out.println(image.getOriginalFilename());
System.out.println(image.getSize());
//保存到文件系统
String path="/images/upload";//WEB路径
path = request.getServletContext()
.getRealPath(path);
System.out.println(path);
//创建upload文件夹
File dir = new File(path);
dir.mkdir();
File file=new File(dir,
image.getOriginalFilename());
//将上载文件保存到文件中
image.transferTo(file);
ResponseResult rr=new ResponseResult();
rr.setState(ResponseResult.STATE_OK);
rr.setMessage("上载成功");
return rr;
}
测试: 先显示上载表单,然后选择文件上载到服务器
上载后可以使用URL显示上载的文件,如:
http://localhost:8080/TeduStore/images/upload/Chrysanthemum.jpg
作业
1,将用户信息打包为Excel文件下载
2,实现将2个图片和图片描述信息上载到服务器
3、day03-Ajax 文件上载
XHR2 XMLHttpRequest2
XHR2提供了异步文件上载功能。
使用步骤是:
-
利用
对象选择获取文件对象
-
创建 FormData 对象用于承载上传文件。
-
将文件对象插入到 FormData 对象 中
-
将 FormData 对象利用Ajax发送到服务器。
JS Ajax 上载
开发步骤:
-
创建上载页面元素:
ajax 上载
选择了:
-
编写脚本显示准备上载的图片:
var images = document.getElementById("images");
var selected=document.getElementById("selected");
images.onchange=function(){
var files = this.files;
selected.innerHTML="";
for(var i=0; i
-
编写Ajax上载脚本:
var btn=document.getElementById("ajax_upload");
btn.onclick=function(){
var files = images.files;
var frm = new FormData();//空白表单
//将文件添加到frm中
for(var i=0; i
-
编写服务器控制器接收文件上载 @RequestMapping(value="
uploadImages.do
", method=RequestMethod.POST) @ResponseBody public ResponseResult uploadImages( @RequestParam("images") MultipartFile[] images, HttpServletRequest request) throws IOException { //保存到文件系统 String path="/images/upload";//WEB路径 path = request.getServletContext() .getRealPath(path); System.out.println(path); //创建upload文件夹 File dir = new File(path); dir.mkdir(); for (MultipartFile image : images) { File file=new File(dir, image.getOriginalFilename()); System.out.println("save:"+file); //将上载文件保存到文件中 image.transferTo(file); }
ResponseResult rr=new ResponseResult();
rr.setState(ResponseResult.STATE_OK);
rr.setMessage("上载成功");
return rr;
}
-
测试
JQuery Ajax 上载
利用JQuery也可以实现Ajax文件上载
-
编写界面
JQuery 上载
选择了:
-
编写脚本显示准备上载的图片
var photos=$("#photos");
var selectedPhotos=$("#selected_photos");
photos.change(function(){
var files=this.files;
selectedPhotos.empty();
for(var i=0; i
-
编写上载脚本:
var ajaxBtn=$("#jquery_upload");
ajaxBtn.click(function(){
var url="uploadImages.do";
var data=new FormData();
var files = photos[0].files;
for(var i=0; i
-
测试
4、密码加密技术(消息摘要技术)
消息摘要: 利用散列算法抽取一组数据的特征,做为这个数据的唯一标识,相当于这组数据的“指纹”
一组数据 -- MD5、SHA散列算法 --> 消息摘要
同样的数据原文具有相同的摘要,不同的原文具有不同的摘要。
消息摘要的用途: 用于检验数据的完整性!
原理:
消息摘要技术广泛用在软件中,用于比较数据的一致性和完整性。
-
迅雷使用消息摘要技术比较下载文件的完整性
-
各种网盘的秒传功能就是利用消息摘要来确认需要上载文件是否与服务器已有文件一致,如果一致就秒传了!
密码加密原理:
消息摘要与密码加密
-
消息摘要是一种检验数据完整性和一致性的技术
-
消息摘要的用途广泛,用途之一是 密码加密
-
消息摘要算法有很多种:MD2 MD5 SHA SHA-1 SHA-256 SHA-384 等
-
常用的有 MD5 SHA
-
消息摘要算法是单向算法,只能根据数据计算摘要,无法反向计算!
-
有摘要反向查询网址,提供了简单字符串的摘要查询!
-
不是反向计算解密的结果!
-
利用摘要加密密码时候,检验使用"加盐"处理,避免反向查询。
修改数据表的列
alter table t_user modify password varchar(50);
消息再要案例:
public class TestCase {
@Test
public void testMd5() throws Exception{
String file = "passwd";
FileInputStream in=new FileInputStream(file);
//计算文件的摘要
//linux 计算摘要命令: md5sum passwd
//mac 计算摘要命令: md5 passwd
String md5=DigestUtils.md5Hex(in);
System.out.println(md5);
in.close();
}
@Test
public void testStringMd5(){
String password="1234";
String md5=DigestUtils.md5Hex(password);
System.out.println(md5);
String salt="今天你吃了吗?";
md5 = DigestUtils.md5Hex(password+salt);
System.out.println(md5);
md5 = DigestUtils.md5Hex(salt+password);
System.out.println(md5);
}
}
更新项目实行密码加密功能:
-
更新配置文件添加“盐”:
今天你吃了吗?
-
更新UserServiceImpl,增加密码加密和加密验证功能:
//从Spring中找到一个BeanID为config的bean,获取
//其salt属性的值,注入到salt变量中
@Value("#{config.salt}")
private String salt;
public void register(
String username,
String password,
String phone,
String email) {
User user = new User();
Date now = new Date();
user.setUsername(username);
//密码摘要加密
System.out.println(salt);
String pwd=DigestUtils.md5Hex(password+salt);
System.out.println(pwd);
user.setPassword(pwd);
user.setPhone(phone);
user.setEmail(email);
user.setDisabled(0);
user.setCreatedTime(now);
user.setCreatedUser("System");
user.setModifiedTime(now);
user.setModifiedUser("System");
register(user);
}
@Transactional
public User login(String username,
String password) {
//为了测试AOP功能添加的 测试代码
System.out.println("登录功能");
if(username.equals("chenghen2")){
System.out.println("异常");
throw new RuntimeException("出异常了");
}
User u = findUserByUsername(username);
if (u == null) {
return null;
} else {
//比较摘要加密以后的密码
String pwd=DigestUtils.md5Hex(password+salt);
if (u.getPassword().equals(pwd)) {
return u;
} else {
return null;
}
}
}
public int updatePassword(Integer uid,
String oldPassword,
String newPassword) {
// 初始化:参数、返回值
int state = -1;
// 处理业务
// 根据uid获取用户信息
User user = userMapper.findUserById(uid);
// 判断用户输入的旧密码是否正确
String pwd=DigestUtils.md5Hex(oldPassword+salt);
if (user.getPassword().equals(pwd)) {
// 密码正确,允许修改
pwd = DigestUtils.md5Hex(newPassword+salt);
userMapper.updatePassword(uid, pwd);
// 给正确的返回值
state = 1;
}
// 返回
return state;
}
作者:Darren
QQ:603026148
以上内容归靳烨所有,如果有什么错误或者不足的地方请联系我,希望我们共同进步。



