2021SC@SDUSC
中午和刘同学一起找戴老师查验了svg demo,进一步明确项目的用例规范方便未来扩展开发。
后端数据库部分,本周分析sdudoc-mysql的图片部分。
文件夹结构:
(古籍文章切分后,字、词组等在前端以svg格式呈现)
可见controller模块分图片、文章两部分,本篇主要分析ImgServiceController、ImgServiceImpl中出现的知识点。(见代码注释)
ImgServiceController
public class ImgServiceController {
@Autowired
ImgService service;
@RequestMapping(value = "/get_latest_id", method = RequestMethod.POST)
public Long getLatestNewId() {
return service.getLatestId() + 1;
}
@RequestMapping(value = "/save_by_base64", method = RequestMethod.POST, produces = "application/json")
public Long save(@RequestBody JSONObject data) {
return service.save(data.getString("base64").replaceAll(" ", "+"), data.getString("filename"));
}
@RequestMapping(value = "/get_by_id", method = RequestMethod.GET)
public byte[] getImgById(Long id) {
return service.getImgById(id);
}
@RequestMapping(value = "/get_by_url", method = RequestMethod.GET)
public byte[] getImgByUrl(String url) {
return Base64Util.base64Decode2Bytes(service.getImgByUrl("" + url));
}
}
此模块核心操作: @RequestMapping
比如:
@RequestMapping(value = "/get_latest_id", method = RequestMethod.POST)
在Spring MVC 中使用 @RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>ServletClass</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletName</servlet-name>
<url-pattern>url</url-pattern>
</servlet-mapping>
关于RequestMethod.POST:
RequestMethod是在@RequestMapping注解中使用的一个属性,用来标识请求的方法类型。
跳转requestMethod源码,可以看到封装进了8种类型:
public enum RequestMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
private RequestMethod() {
}
}
tips:
对于spring接口的method的get和post定义,在访问时这两种方式的效果有不同:
①将一个method定义成RequestMethod.GET时,可以直接通过地址访问,这非常方便我们在开发的时候调用到我们的接口并进行测试;
②同样的接口,将其method更改为RequestMethod.POST时,会发现接口在地址栏访问不了了,只有向服务器发起一个POST请求时才可以访问。
ImgServiceImpl
实现了ImgService接口,跳转查看ImgService :
public interface ImgService {
public Long getLatestId();
public Long save(String base64, String filename);
public Long save(byte[] data);
public byte[] getImgById(Long id);
public byte[] getImgByUrl(String url);
public Img fileChecksumExist(String checksum) throws IOException;
}
package cn.edu.sdu.service.impl;
import cn.edu.sdu.entity.ds1.Img;
import cn.edu.sdu.repository.ds1.ImgRepository;
import cn.edu.sdu.service.ImgService;
import cn.edu.sdu.util.Base64Util;
import cn.edu.sdu.util.FileChecksum;
import cn.edu.sdu.util.RandomPicNameUtil;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
@Service
public class ImgServiceImpl implements ImgService {
final ImgRepository repository;
public ImgServiceImpl(ImgRepository repository) {
this.repository = repository;
}
@Override
public Long getLatestId() {
Img img = new Img();
return repository.count(Example.of(img));
}
@Override
public Long save(String base64, String filename) {
String[] d = base64.split("base64,");
if (d.length == 2) {
// String prefix = d[0];
String data = d[1];
byte[] bs = Base64Util.base64Decode2Bytes(data);
for(int i = 0 ; i < bs.length; ++i) {
if(bs[i] < 0) {
//调整异常数据
bs[i] += 256;
}
}
String imgFilePath = generateImgUrl(filename);
try {
// 如果成功写入文件,记录在数据库里
if (writeInFileByData(bs, imgFilePath)) {
// 比对校验和,如果数据库里没有,则写入数据库
String checksum = FileChecksum.checksumSHA256(bs);
Img img;
if ((img = fileChecksumExist(checksum)) == null) {
img = new Img();
img.setId(getLatestId() + 1L);
img.setUrl(imgFilePath);
img.setSha256(checksum);
repository.save(img);
return img.getId();
}
else {
// 数据库里有,则返回图片id
return img.getId();
// return randomName;
}
} else {
return -4L; // 写入文件失败
}
} catch (IOException e) {
return -2L;
}
} else {
return -3L;
// return "图片格式不正确";
}
}
@Override
public Long save(byte[] data) {
return null;
}
public boolean writeInFileByData(byte[] data, String imgFilePath) {
boolean result = false;
// 写入file
OutputStream out = null;
try {
out = new FileOutputStream(imgFilePath);
out.write(data);
out.flush();
out.close();
result = true;
} catch (IOException e) {
// return -2L;
// return "图片上传失败";
}
return result;
}
public String generateImgUrl(String filename) {
// 生成图片存储路径
String randomName = RandomPicNameUtil.getRandomName(filename);
String imgFilePath = System.getProperty("user.dir");
char separator = '/';
if (imgFilePath.indexOf('/') < 0) {
separator = '\\';
}
String dirName = separator + "webapps"
+ separator + "assets"
+ separator + "picture"
+ separator;
File dir = new File(imgFilePath + dirName);
if (!dir.exists() && !dir.mkdirs()) {
// return -1L;
// return "生成图片存储路径失败";
return null;
}
imgFilePath = imgFilePath + dirName + randomName;
return imgFilePath;
}
@Override
public byte[] getImgById(Long id) {
Optional<Img> op = repository.findById(id);
if (op.isPresent()) {
Img img = op.get();
// 读取图片
return getImgByUrl(img.getUrl());
} else {
return "找不到图片".getBytes(StandardCharsets.UTF_8);
}
}
public byte[] getImgByUrl(String url) {
try {
InputStream in = new FileInputStream(url);
byte[] data = new byte[in.available()];
int n;
while ((n = in.read(data)) == -1) break;
in.close();
return Base64Util.base64Encode2Bytes(data);
} catch (IOException e) {
e.printStackTrace();
return "图片读取失败".getBytes(StandardCharsets.UTF_8);
}
}
/**
* 返回校验和是否存在
* 存在返回Img,不存在返回null
* */
@Override
public Img fileChecksumExist(String checksum) {
Img img = new Img();
img.setSha256(checksum);
Optional<Img> one = repository.findOne(Example.of(img));
return one.orElse(null);
}
public static void main(String[] args) {
String imgFilePath = System.getProperty("user.dir");
File dir = new File(imgFilePath + "\\webapps\\assets\\picture\\");
System.out.println(dir.getPath());
if (!dir.exists()) {
System.out.println(dir.mkdirs());
}
}
}