欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > JS+Springboot做一个交互Demo

JS+Springboot做一个交互Demo

2024/10/25 15:02:16 来源:https://blog.csdn.net/qq_41307963/article/details/143227366  浏览:    关键词:JS+Springboot做一个交互Demo

背景:老大做了一个 SDK,包含字符加解密、文件加解密,要求能从前端访问,并且能演示的 Demo。
思路:html 写页面,js 发送请求,freemarker 做简单的参数交互,JAVA 后端处理。
一、项目依赖
● java17
● springboot 3.1.2
● 模板技术:spring-boot-starter-freemarker 2.3.32
● 工具包:commons-io 2.16.0
● pom 文件:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>com.xxx.xx.x</groupId><artifactId>xx-x</artifactId><version>3.0-SNAPSHOT</version></parent><artifactId>x-sdk-service</artifactId><modelVersion>4.0.0</modelVersion><description>sdk 项目服务</description><packaging>jar</packaging><name>sdk-service</name><properties><jdk.version>17</jdk.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>3.1.2</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><!-- SpringBoot 拦截器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- Spring框架基本的核心工具 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency><!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.8</version><scope>test</scope><exclusions><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId><exclusions><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion><exclusion><artifactId>logback-classic</artifactId><groupId>ch.qos.logback</groupId></exclusion></exclusions></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.30</version><exclusions><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><!-- 前端渲染视图技术 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!-- https://mvnrepository.com/artifact/commons-io/commons-io --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.16.1</version></dependency></dependencies></project>

二、前端代码

使用的模板技术,JS + Freemark。“${baseUrl}”指向的是后端配置的IP地址,可改为静态的,但是那样html页面就写死了。文件放在项目:resource/templates下,无则需要创建。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>演示页</title>
</head>
<script>// 访问地址const baseUrl = "${baseUrl}"/*** 加密*/function getEnc() {// 处理传入数据let data = document.getElementById("encText").value;data = btoa(data);// 组装请求const oReq = new XMLHttpRequest();const url = baseUrl + "/enc?data=" + data;console.log("request " + url)oReq.open("GET", url, true);// 响应类型oReq.responseType = "text";oReq.onprogress = function (result) {console.log(result)// 失败处理if (fail(result)) {return;}// 处理响应const data = result.currentTarget.response;let parse = JSON.parse(data);const text = parse.data;document.getElementById("decText").value = String(text);};oReq.send();}/*** 解密*/function getDec() {let data = document.getElementById("decText").value;const oReq = new XMLHttpRequest();data = btoa(data);const url = baseUrl + "/dec?data=" + data;console.log("request " + url)oReq.open("GET", url, true);// 响应类型oReq.responseType = "text";oReq.onprogress = function (result) {console.log(result)if (fail(result)) {return;}const data = result.currentTarget.response;let parse = JSON.parse(data);const text = parse.data;document.getElementById("encText").value = String(atob(text));};oReq.send();}/*** 文件加密*/function getEncFile() {const fileInput = document.getElementById('encFile');const file = fileInput.files[0];let formData = new FormData();formData.append("file", file)const oReq = new XMLHttpRequest();const url = baseUrl + "/encFile";console.log("request " + url)oReq.open("POST", url, true);// 响应类型oReq.onprogress = function (result) {console.log(result)if (fail(result)) {return;}const data = result.currentTarget.response;let parse = JSON.parse(data);const fileName = parse.data;// 下载文件downloadFile(baseUrl + "/downLoadFile/" + fileName, fileName)// 原组件置空fileInput.value = '';};oReq.send(formData);}/*** 文件解密*/function getDecFile() {const fileInput = document.getElementById('decFile');const file = fileInput.files[0];let formData = new FormData();formData.append("file", file)const oReq = new XMLHttpRequest();const url = baseUrl + "/decFile";console.log("request " + url)oReq.open("POST", url, true);// 响应类型oReq.onload = function (result) {console.log(result)if (fail(result)) {console.log("encFile:" + result)return;}const data = result.currentTarget.response;let parse = JSON.parse(data);const fileName = parse.data;downloadFile(baseUrl + "/downLoadFile/" + fileName, fileName)fileInput.value = '';};oReq.send(formData);}/*** 下载文件* @param url* @param fileName*/function downloadFile(url, fileName) {console.log("downloadFile:" + url)console.log("downloadFile fileName:" + fileName)fetch(url).then(response => response.blob()).then(blob => {const link = document.createElement('a');link.href = URL.createObjectURL(blob);link.download = fileName;link.target = "_blank"; // 可选,如果希望在新窗口中下载文件,请取消注释此行link.click();});}/*** 请求是否失败* @param result 请求* @returns {boolean} true 失败*/function fail(result) {const data = result.currentTarget.response;let parse = JSON.parse(data);if (200 !== parse.code) {alert("请求失败:" + parse.msg)return true;}return false;}</script>
<body style="text-align: center;margin-top: auto">
<h1>加密工具演示页</h1>
<!-- 文本加密 -->
<div style="margin-top: 48px"><h3>文本加密</h3><div><input id="encText" type="text" style="width: 200px;"/><button onclick="getEnc();" style="margin-left: 12px">加密</button></div><div style="margin-top: 12px"><input id="decText" type="text" style="width: 200px;"/><button onclick="getDec();" style="margin-left: 12px">解密</button></div>
</div>
<!-- 文件加密 -->
<div style="margin-top: 48px;"><h3>文件加解密</h3><div style="margin-top: 24px">文件加密:<input id="encFile" type="file" onchange="getEncFile()"/></div><div style="margin-top: 24px;">文件解密:<input id="decFile" type="file" onchange="getDecFile()"/></div>
</div>
</body>
</html>

三、后端配置

application配置文件

server:port: 12321tmv:baseUrl: http://localhost:12321baseDir: ./config/# application.yml
spring:servlet:multipart:max-file-size: 10000MBmax-request-size: 10000MB#配置freemarkerfreemarker:#指定HttpServletRequest的属性是否可以覆盖controller的model的同名项allow-request-override: false#req访问requestrequest-context-attribute: req#后缀名freemarker默认后缀为.ftl,当然你也可以改成自己习惯的.htmlsuffix: .ftl#设置响应的内容类型content-type: text/html;charset=utf-8#是否允许mvc使用freemarkerenabled: true#是否开启template cachingcache: false#设定模板的加载路径,多个以逗号分隔,默认: [“classpath:/templates/”]template-loader-path: classpath:/templates/#设定Template的编码charset: UTF-8# 设置静态文件路径,js,css等mvc:static-path-pattern: /static/**

四、后端代码

@RestController
@RequestMapping
@Slf4j
public class EncryptController {@Value("${tmv.baseUrl:http://localhost:12321}")String baseUrl;@Value("${tmv.baseDir:D:\\temp\\temp\\}")String baseDir;private static KmService kmService;/*** 初始化 SDK*/@PostConstructpublic void init() {try {log.info("load kmService start, baseDir: {}", baseDir);kmService = KmService.getInstance(baseDir);log.info("load kmService success");} catch (Exception e) {log.error("SDK加载失败,请检查");log.error("load kmService error", e);}}@RequestMapping("/")public ModelAndView index() {// 跳转到index.ftl 模板ModelAndView mv = new ModelAndView("index");// 添加属性mv.addObject("baseUrl", baseUrl);return mv;}@GetMapping("enc")public TResult enc(@RequestParam String data) {log.info("enc request: {}", data);String result;try {result = kmService.enc(data, null);} catch (Exception e) {log.error("enc error", e);result = e.getMessage();}log.info("enc resp: {}", result);return TResult.success(result);}@GetMapping("dec")public TResult dec(@RequestParam String data) {log.info("dec : {}", data);// 需要转码byte[] bytes = Base64.decodeBase64(data);log.info("dec : {}", data);String result;try {result = kmService.dec(new String(bytes), null);} catch (Exception e) {log.error("dec error", e);result = e.getMessage();}log.info("dec resp: {}", result);return TResult.success(result);}@PostMapping("encFile")public TResult encFile(@RequestParam MultipartFile file) {log.info("fileName request: {}", file.getOriginalFilename());long size = file.getSize();log.info("file size: {} bit {} kb", size, size / 1000);String result;try {// 创建临时文件File tempFile = File.createTempFile(System.currentTimeMillis() + "", "");byte[] bytes = file.getBytes();FileUtils.copyInputStreamToFile(new ByteArrayInputStream(bytes), tempFile);File destFile = new File(baseDir + UUIDGenerator.getUUID() + ".enc.txt", "");// 加密boolean flag = kmService.fileEncrypt(tempFile.getAbsolutePath(), destFile.getAbsolutePath());if (flag) {result = destFile.getName();} else {throw new RuntimeException("处理失败,请检查输入信息是否有误");}} catch (Exception e) {log.error("encFile error", e);return TResult.fail(e.getMessage());}log.info("enc resp: {}", result);return TResult.success(result);}@PostMapping("decFile")public TResult decFile(@RequestParam MultipartFile file) {log.info("decFile fileName request: {}", file.getOriginalFilename());long size = file.getSize();log.info("file size: {} bit {} kb", size, size / 1000);String result;try {// 创建临时文件File tempFile = File.createTempFile(System.currentTimeMillis() + "", "");byte[] bytes = file.getBytes();FileUtils.copyInputStreamToFile(new ByteArrayInputStream(bytes), tempFile);File destFile = new File(baseDir + UUIDGenerator.getUUID() + ".dec.txt", "");// 加密boolean flag = kmService.fileDecrypt(tempFile.getAbsolutePath(), destFile.getAbsolutePath());if (flag) {result = destFile.getName();} else {throw new RuntimeException("处理失败,请检查输入信息是否有误");}} catch (Exception e) {log.error("decFile error", e);return TResult.fail(e.getMessage());}log.info("enc resp: {}", result);return TResult.success(result);}@GetMapping("downLoadFile/{fileName}")public void downLoadFile(HttpServletResponse response, @PathVariable("fileName") String fileName) throws IOException {log.info("downLoadFile fileName request: {}", fileName);String filePath = baseDir + fileName;log.info("filePath :{}", filePath);File file = new File(filePath);try {copy2respond(response, file);} catch (Exception e) {log.error("decFile error", e);}}/*** 文件转下载流** @param response 响应* @param file     文件* @throws IOException 异常*/private static void copy2respond(HttpServletResponse response, File file) throws IOException {response.setContentType("application/octet-stream");response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());FileInputStream fileInputStream = new FileInputStream(file);OutputStream out = response.getOutputStream();byte[] buffer = new byte[4096];int length;while ((length = fileInputStream.read(buffer)) > 0) {out.write(buffer, 0, length);}out.flush();fileInputStream.close();}}

响应对象

@Data
public class TResult implements Serializable {private static final long serialVersionUID = 1L;@Schema(description = "响应码")@Getterprivate int code;@Schema(description = "响应消息")@Getterprivate String msg;@Schema(description = "响应数据")@Getterprivate Object data;public static TResult success(Object data){TResult tResult = new TResult();tResult.setCode(200);tResult.setMsg("OK");tResult.setData(data);return tResult;}public static TResult fail(String messag){TResult tResult = new TResult();tResult.setCode(500);tResult.setMsg(messag);tResult.setData(null);return tResult;}
}

五、页面效果

在这里插入图片描述

最后,作为一个Javaer,会点前端是OK的。但,技不外露,最好不要随便接前端需求。还好最终老大放了一条生路,否则笔者大概率要学习深入理解Html + css + JavaScript了。
(因为笔者觉得只是两个输入框所以自告奋勇的接下来,谁知道后面又要加远程访问、文件加解密、UI优化、全局异常捕获、人性化提示…差点翻车)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com