学完五大框架,上手跟着慕课视频做个项目练手https://coding.imooc.com/class/144.html#Anchor
刚做完1.0,对跟着老师学习到的实用技术做个小结
上传图片的处理(调用Thumbnails生成带有水印的图片)
下载thumbnailator-0.4.8.jar
实体类ImageHolder封装上传文件的名字(后面需要获取格式扩展名时用到)和输入流
public class ImageHolder {
private String imageName;
private InputStream image;
public ImageHolder(String imageName, InputStream image) {
this.imageName = imageName;
this.image = image;
}
public String getImageName() {
return imageName;
}
}
public class ImageUtil {
private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
private static final Random r = new Random();
/**
* 处理缩略图,并返回新生成图片的相对值路径
*
* @param thumbnail
* @param targetAddr
* @return
*/
public static String generateThumbnail(ImageHolder thumbnail, String targetAddr) {
// 获取不重复的随机名
String realFileName = getRandomFileName();
// 获取文件的扩展名如png,jpg等
String extension = getFileExtension(thumbnail.getImageName());
// 如果目标路径不存在,则自动创建
makeDirPath(targetAddr);
// 获取文件存储的相对路径(带文件名)
String relativeAddr = targetAddr + realFileName + extension;
// 获取文件要保存到的目标路径
File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
// 调用Thumbnails生成带有水印的图片
try {
Thumbnails.of(thumbnail.getImage()).size(200, 200)
.watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.jpg")), 0.25f)
.outputQuality(0.8f).toFile(dest);
} catch (IOException e) {
logger.error(e.toString());
throw new RuntimeException("创建缩略图失败:" + e.toString());
}
// 返回图片相对路径地址
return relativeAddr;
}
/**
* 创建目标路径所涉及到的目录,即/home/work/xiangze/xxx.jpg, 那么 home work xiangze
* 这三个文件夹都得自动创建
*
* @param targetAddr
*/
private static void makeDirPath(String targetAddr) {
String realFileParentPath = PathUtil.getImgBasePath() + targetAddr;
File dirPath = new File(realFileParentPath);
if (!dirPath.exists()) {
dirPath.mkdirs();
}
}
/**
* 获取输入文件流的扩展名
*
* @param thumbnail
* @return
*/
private static String getFileExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf("."));
}
/**
* 生成随机文件名,当前年月日小时分钟秒钟+五位随机数
*
* @return
*/
public static String getRandomFileName() {
// 获取随机的五位数
int rannum = r.nextInt(89999) + 10000;
String nowTimeStr = sDateFormat.format(new Date());
return nowTimeStr + rannum;
}
/**
* storePath是文件的路径还是目录的路径, 如果storePath是文件路径则删除该文件,
* 如果storePath是目录路径则删除该目录下的所有文件
*
* @param storePath
*/
public static void deleteFileOrPath(String storePath) {
File fileOrPath = new File(PathUtil.getImgBasePath() + storePath);
if (fileOrPath.exists()) {
if (fileOrPath.isDirectory()) {
File files[] = fileOrPath.listFiles();
for (int i = 0; i < files.length; i++) {
files[i].delete();
}
}
fileOrPath.delete();
}
}
}
水印的透明度可以通过改变最后的参数来调整,0.0F是完全透明的,1.0F是完全不透明的。
public class PathUtil {
private static String seperator = System.getProperty("file.separator");
public static String getImgBasePath() {
String os = System.getProperty("os.name");
String basePath = "";
if (os.toLowerCase().startsWith("win")) {
basePath = "C:/o2oImg";
} else {
basePath = "/user/image";
}
basePath = basePath.replace("/", seperator);
return basePath;
}
public static String getShopImagePath(long shopId) {
String imagePath = "/upload/shop/" + shopId + "/";
return imagePath.replace("/", seperator);
}
}
在service层调用的时候
private void addShopImg(Shop shop, ImageHolder thumbnail) {
// 获取shop图片目录的相对值路径
String dest = PathUtil.getShopImagePath(shop.getShopId());
String shopImgAddr = ImageUtil.generateThumbnail(thumbnail, dest);
shop.setShopImg(shopImgAddr);
}
往 getShopImagePath(long shopId) 中传入shopid值拼接成/upload/shop/shopid的路径
ImageUtil.generateThumbnail(thumbnail, dest)方法 dest+随机名+文件扩展名=相对路径 返回来
PathUtil.getImgBasePath() +相对路径=真实存储路径 方法中判断系统是win或者是其他,统一先把分隔符写成 ‘/’ imagePath.replace("/", seperator)再判断进行替换
Ajax发送表单数据
<!-- json解析 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
$('#submit').click(function() {
var shop = {};
shop.shopName = $('#shop-name').val();
shop.shopAddr = $('#shop-addr').val();
shop.phone = $('#shop-phone').val();
shop.shopDesc = $('#shop-desc').val();
shop.shopCategory = {
shopCategoryId : $('#shop-category').find('option').not(function() {
return !this.selected;
}).data('id')
};
shop.area = {
areaId : $('#area').find('option').not(function() {
return !this.selected;
}).data('id')
};
var shopImg = $("#shop-img")[0].files[0];
var formData = new FormData();
formData.append('shopImg', shopImg);
formData.append('shopStr', JSON.stringify(shop));
var verifyCodeActual = $('#j_captcha').val();
if (!verifyCodeActual) {
$.toast('请输入验证码!');
return;
}
formData.append("verifyCodeActual", verifyCodeActual);
$.ajax({
url : editShopUrl,
type : 'POST',
// contentType: "application/x-www-form-urlencoded; charset=utf-8",
data : formData,
contentType : false,
processData : false,
cache : false,
success : function(data) {
if (data.success) {
$.toast('提交成功!');
if (isEdit){
$('#captcha_img').click();
} else{
window.location.href="/myO2O/shopadmin/shoplist";
}
} else {
$.toast('提交失败!');
$('#captcha_img').click();
}
}
});
});
async:
要求为Boolean类型的参数,默认设置为true,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为false。注意,同步请求将锁住浏览器,用户其他操作必须等待请求完成才可以执行。
这里就会经常发生问题,就是异步了,所以有时候你会不小心,在请求还没成功,你就以为你成功了,然后再干其他事,就容易出问题,所以,一般要在success回调函数里面做一些事。
cache:
要求为Boolean类型的参数,默认为true(当dataType为script时,默认为false),设置为false将不会从浏览器缓存中加载请求信息。
contentType:
要求为String类型的参数,当发送信息至服务器时,内容编码类型默认为"application/x-www-form-urlencoded"。该默认值适合大多数应用场合。
multipart/form-data:有时候也会这个,上传下载可能会用到。
contentType: "application/json; charset=utf-8",
success:
要求为Function类型的参数,请求成功后调用的回调函数,有两个参数。
(1)由服务器返回,并根据dataType参数进行处理后的数据。
(2)描述状态的字符串。
function(data, textStatus){
//data可能是xmlDoc、jsonObj、html、text等等
this; //调用本次ajax请求时传递的options参数
}
error:
要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数,即XMLHttpRequest对象、错误信息、捕获的错误对象(可选)。ajax事件函数如下:
function(XMLHttpRequest, textStatus, errorThrown){
//通常情况下textStatus和errorThrown只有其中一个包含信息
this; //调用本次ajax请求时传递的options参数
}
前端把对象转化为json字符串,后台接受可以这样:
String shopStr = HttpServletRequestUtil.getString(request, "shopStr");
ObjectMapper mapper = new ObjectMapper();
Shop shop = mapper.readValue(shopStr, Shop.class);
更粗暴的是传进来的参数加@RequestBody,直接先将字符串转换成对象Shop
getJSON获取页面信息
这个项目页面获取从后台传来的信息,全部都是用getJSON啊。。。用getJSON比之前用的JSP搭配jstl,更加前后分离啦
modelMap.put("shopCategoryList", shopCategoryList);
modelMap.put("areaList", areaList);
modelMap.put("success", true);
function getCategory() {
$.getJSON(initUrl, function(data) {
if (data.success) {
var tempHtml = '';
var tempAreaHtml = '';
data.shopCategoryList.map(function(item, index) {
tempHtml += '<option data-id="' + item.shopCategoryId
+ '">' + item.shopCategoryName + '</option>';
});
data.areaList.map(function(item, index) {
tempAreaHtml += '<option data-id="' + item.areaId + '">'
+ item.areaName + '</option>';
});
$('#shop-category').html(tempHtml);
$('#shop-category').removeAttr('disabled');
$('#area').html(tempAreaHtml);
}
});
}
jq数据请求的四种方法get post ajax getJSON和不同于之间的jsonp跨域请求详细总结
后台对文件流的处理
CommonsMultipartFile shopImg = null;
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
if (commonsMultipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multipartHttpServletRequest =(MultipartHttpServletRequest) request;
shopImg = (CommonsMultipartFile)=multipartHttpServletRequest.getFile("shopImg");
}
ImageHolder imageHolder = new ImageHolder(shopImg.getOriginalFilename(), shopImg.getInputStream());
CommonsMultipartResolver的使用:
1、得到CommonsMultipartResolver对象:
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext()); //其中request即为我们请求的HttpServletRequest对象
2、判断请求是否为MultiPart File文件上传请求:
boolean isFileUpload = multipartResolver.isMultipart(request);
MultipartHttpServletRequest的使用:
在确定了是多文件上传的请求后,即可以将HttpServletRequest转成MultipartHttpServletRequest对象,MultipartHttpServletRequest对象封装了文件上传的文件对象,可以通过此对象直接得到文件对象。
1、得到文件名称列表的迭代器:
Iterator<String> iter = multiRequest.getFileNames();
2、取得上传的文件:
MultipartFile file = multiRequest.getFile(iter.next());
跟之前做的直接的文件上传做下对比:
@PostMapping
public void fileUpload(MultipartFile[] files) throws IllegalStateException, IOException {
ModelAndView mv=new ModelAndView();
for(MultipartFile multipartFile:files) {
String originFileName=multipartFile.getOriginalFilename();
String newFileName=UUID.randomUUID()+"."+FilenameUtils.getExtension(originFileName);
String root=request.getServletContext().getRealPath("/upload");
File uploadRoot=new File(root);
if(!uploadRoot.exists()) {
uploadRoot.mkdirs();
}
multipartFile.transferTo(new File(uploadRoot,newFileName));
}
}
服务器部署
阿里云部署Java网站和微信开发调试心得技巧(上)
阿里云部署Java网站和微信开发调试心得技巧(下)阿里云部署Java网站和微信开发调试心得技巧(下)
部署到tomcat的时候出现了很多麻烦的问题,网站还没有备案,80端口不能用估计一直没成功过,这样也导致了后面的微信开发没办法做。。。
最后只能先ip+8080端口访问啦