diff --git b/.gitignore a/.gitignore new file mode 100644 index 0000000..2140a37 --- /dev/null +++ a/.gitignore @@ -0,0 +1,32 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git b/README.md a/README.md new file mode 100644 index 0000000..3a667c7 --- /dev/null +++ a/README.md @@ -0,0 +1,6 @@ +**配置SN文件路径:** +在resources下设置**application.properties**文件中的**SN.file.path**属性(该属性是存储SN的文件的路径,文件格式是txt,例:D:/temp/SN.txt) +以及设置**SN.file.temp.path**属性(该属性是SN备份文件的路径,文件格式是txt,例:D:/temp/SNTemp.txt) + +**配置日志文件路径:** +在resources下设置**log4j2.xml**文件中"Property name="baseDir" value="./log"/"标签内的value值(该值为存储日志文件的文件夹路径,例:D:/temp/log) diff --git b/pom.xml a/pom.xml new file mode 100644 index 0000000..1289f08 --- /dev/null +++ a/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + + com.haoge + SNManageDemo + 1.0 + + + + + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + io.springfox + springfox-swagger2 + 2.7.0 + + + io.springfox + springfox-swagger-ui + 2.7.0 + + + + cn.hutool + hutool-http + 4.1.14 + + + org.projectlombok + lombok + 1.16.10 + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + + + + + + + src/main/java + + **/*.xml + + + + src/main/resources + + **/*.* + + + + + + \ No newline at end of file diff --git b/src/main/java/com/example/demo/SNManageApplication.java a/src/main/java/com/example/demo/SNManageApplication.java new file mode 100644 index 0000000..40e2d6f --- /dev/null +++ a/src/main/java/com/example/demo/SNManageApplication.java @@ -0,0 +1,16 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + + +@SpringBootApplication +@EnableSwagger2 +public class SNManageApplication { + + public static void main(String[] args) { + SpringApplication.run(SNManageApplication.class, args); + } + +} diff --git b/src/main/java/com/example/demo/controller/SNController.java a/src/main/java/com/example/demo/controller/SNController.java new file mode 100644 index 0000000..3d4a709 --- /dev/null +++ a/src/main/java/com/example/demo/controller/SNController.java @@ -0,0 +1,90 @@ +package com.example.demo.controller; + +import com.example.demo.exception.SNRepetitiveException; +import com.example.demo.service.SNService; +import com.example.demo.util.HttpResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Api(tags = "SN操作") +@Controller +public class SNController { + static Logger logger = LogManager.getLogger(SNController.class); + + @Autowired + SNService snService; + + @ApiOperation("首页") + @GetMapping("/index.html") + public String index() { + return "Index"; + } + + @ApiOperation("添加SN") + @PostMapping("/add_SN") + @ResponseBody + public HttpResult addSN(@RequestBody String SNDto) { + + try { + snService.addSN(SNDto); + return HttpResult.success("添加成功"); + } catch (SNRepetitiveException e) { + return HttpResult.fail("SN已存在,请勿重复添加!"); + } catch (Exception e) { + logger.error(e.getMessage()); + return HttpResult.fail(); + } + + } + + +// @ApiOperation("获取全部SN") +// @GetMapping("/get_SNs") +// @ResponseBody +// public void getSNs(HttpServletRequest request, HttpServletResponse response) { +// try { +// snService.downloadSNFile(request, response); +// } catch (Exception e) { +// response.setStatus(500); +// } +// +// } + + @ApiOperation("获取全部base64加密后的SN") + @GetMapping("/get_SNs") + @ResponseBody + public HttpResult getBase64SNs() throws IOException { + try { + return HttpResult.success("",snService.getEncryptSNs()); + } catch (Exception e) { + logger.error(e.getMessage()); + return HttpResult.fail("服务器异常"); + } + + } + + @ApiOperation("删除指定SN") + @PostMapping("/delete_SN") + @ResponseBody + public HttpResult deleteSN(@RequestBody String SN) { + try { + snService.deleteSN(SN); + return HttpResult.success("SN已删除或不存在!"); + } + catch (Exception e) { + logger.error(e.getMessage()); + return HttpResult.fail("服务器异常!"); + } + } + + +} diff --git b/src/main/java/com/example/demo/exception/SNRepetitiveException.java a/src/main/java/com/example/demo/exception/SNRepetitiveException.java new file mode 100644 index 0000000..4299727 --- /dev/null +++ a/src/main/java/com/example/demo/exception/SNRepetitiveException.java @@ -0,0 +1,11 @@ +package com.example.demo.exception; + +public class SNRepetitiveException extends Exception{ + + public SNRepetitiveException() {} + + public SNRepetitiveException(String message) { + super(message); + } + +} diff --git b/src/main/java/com/example/demo/service/SNService.java a/src/main/java/com/example/demo/service/SNService.java new file mode 100644 index 0000000..998f80c --- /dev/null +++ a/src/main/java/com/example/demo/service/SNService.java @@ -0,0 +1,34 @@ +package com.example.demo.service; + +import com.example.demo.exception.SNRepetitiveException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.FileNotFoundException; +import java.io.IOException; + +public interface SNService { + /** + * 新增SN号 + * @param SN SN号 + */ + void addSN(String SN) throws SNRepetitiveException, IOException; + + /** + * 下载所有SN号 + */ + void downloadSNFile(HttpServletRequest request, HttpServletResponse response) throws IOException; + + /** + * 获取所有加密后的SN字符串 + * @return - + */ + String getEncryptSNs() throws IOException; + + /** + * 删除指定SN记录 + * @param SN SN号 + */ + void deleteSN(String SN) throws Exception; + +} diff --git b/src/main/java/com/example/demo/service/impl/SNServiceImpl.java a/src/main/java/com/example/demo/service/impl/SNServiceImpl.java new file mode 100644 index 0000000..b46ea99 --- /dev/null +++ a/src/main/java/com/example/demo/service/impl/SNServiceImpl.java @@ -0,0 +1,146 @@ +package com.example.demo.service.impl; + +import cn.hutool.core.codec.Base64; +import com.example.demo.exception.SNRepetitiveException; +import com.example.demo.service.SNService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +@Service +public class SNServiceImpl implements SNService { + /** + * 多线程改写文件存在并发问题,需加锁操作 + */ + private static final Lock lock = new ReentrantLock(); + + @Value("${SN.file.path}") + String SNFilePath; + + @Value("${SN.file.temp.path}") + String SNTempFilePath; + + @Override + public void addSN(String SNDto) throws SNRepetitiveException, IOException { + //加try,catch只为释放锁 + try { + //加锁 + lock.lock(); + + //读取文件,判断SN是否重复 + Set set = new HashSet<>(); + BufferedReader bufferedReader = new BufferedReader(new FileReader(SNFilePath)); + String br; + while ((br=bufferedReader.readLine()) != null) { + //截取SN + int index = br.indexOf('#'); + String SN = br.substring(0,index == -1? 0 : index); + set.add(SN); + } + + String addSn = SNDto.substring(0,SNDto.indexOf('#')); + if (set.contains(addSn)) { + throw new SNRepetitiveException("SN:" + addSn + " 已存在,请勿重复添加"); + } + + //写入 + FileWriter fileWriter = new FileWriter(SNFilePath,true); + fileWriter.write(SNDto+System.lineSeparator()); + fileWriter.flush(); + fileWriter.close(); + } finally { //释放锁 + lock.unlock(); + } + } + + @Override + public String getEncryptSNs() throws IOException { + File file = new File(SNFilePath); + //读取文件 + byte[] SNsByteArr = new byte[(int) file.length()]; + FileInputStream fileInputStream = new FileInputStream(file); + fileInputStream.read(SNsByteArr); + //加密 + String encodeSNs = Base64.encode(SNsByteArr); + + return encodeSNs; + } + + @Override + public void deleteSN(String SN) throws Exception{ + try { + lock.lock(); + + //读取文件,记录不用删除的数据 + BufferedReader bufferedReader = new BufferedReader(new FileReader(SNFilePath)); + String br; + StringBuilder stringBuilder = new StringBuilder(); + boolean SNExist = false; + while ((br=bufferedReader.readLine()) != null) { + //截取SN + int index = br.indexOf('#'); + String str = br.substring(0,index == -1? 0 : index); + if (!SN.equals(str)) { + stringBuilder.append(br); + stringBuilder.append(System.lineSeparator()); + } else { + SNExist = true; + } + } + bufferedReader.close(); + + //如果存在要删除的SN,先将数据备份,再将留存数据覆盖掉原SN文件,避免数据写一半断电丢失。 + if (SNExist) { + //备份数据 + FileWriter SNTempfileWriter = new FileWriter(SNTempFilePath); + SNTempfileWriter.write(stringBuilder.toString()); + SNTempfileWriter.flush(); + SNTempfileWriter.close(); + //覆盖掉原来的数据到SN文件中 + FileWriter SNfileWriter = new FileWriter(SNFilePath); + SNfileWriter.write(stringBuilder.toString()); + SNfileWriter.flush(); + SNfileWriter.close(); + + } + + + } finally { + lock.unlock(); + } + } + + @Override + public void downloadSNFile(HttpServletRequest request, HttpServletResponse response) throws IOException { + File file = new File(SNFilePath); + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-type","application/octet-stream;charset=UTF-8"); + response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(file.getName().trim(), "UTF-8")); + response.addHeader("Pargam", "no-cache"); + response.addHeader("Cache-Control", "no-cache"); + + //读取文件 + byte[] SNsByteArr = new byte[(int) file.length()]; + FileInputStream fileInputStream = new FileInputStream(file); + fileInputStream.read(SNsByteArr); + //加密 + String encodeSNs = Base64.encode(SNsByteArr); + + //写入到输出流 + response.addHeader("Content-Length",String.valueOf(encodeSNs.getBytes().length)); + OutputStream outputStream = response.getOutputStream(); + outputStream.write(encodeSNs.getBytes()); + outputStream.flush(); + outputStream.close(); + + } + +} diff --git b/src/main/java/com/example/demo/util/HttpResult.java a/src/main/java/com/example/demo/util/HttpResult.java new file mode 100644 index 0000000..3ae4f6c --- /dev/null +++ a/src/main/java/com/example/demo/util/HttpResult.java @@ -0,0 +1,40 @@ +package com.example.demo.util; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class HttpResult implements Serializable { + public static final int CODE_SUCCESS = 200; + public static final int CODE_FAILED = 500; + + private Integer code; + + private String message; + + private T data; + + public static HttpResult success() { + return new HttpResult<>(200,"success",null); + } + + public static HttpResult success(String message) { + return new HttpResult<>(200,message,null); + } + + public static HttpResult success(String message, T data) { + return new HttpResult<>(200,message,data); + } + + public static HttpResult fail() { + return new HttpResult<>(500,"fail",null); + } + public static HttpResult fail(String message) { + return new HttpResult<>(500,message,null); + } +} diff --git b/src/main/resources/application.properties a/src/main/resources/application.properties new file mode 100644 index 0000000..f75ccf0 --- /dev/null +++ a/src/main/resources/application.properties @@ -0,0 +1,19 @@ + server.port=8080 + + +spring.web.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ + + +logging.config=classpath:log4j2.xml + +#swagger.basic.enable = true +#swagger.basic.username = test +#swagger.basic.password = 123 + +spring.thymeleaf.cache=false +spring.thymeleaf.prefix=classpath:/templates/ +spring.thymeleaf.suffix=.html + + +SN.file.path=D:/temp/SN.txt +SN.file.temp.path=D:/temp/SNTemp.txt \ No newline at end of file diff --git b/src/main/resources/log4j2.xml a/src/main/resources/log4j2.xml new file mode 100644 index 0000000..78f571f --- /dev/null +++ a/src/main/resources/log4j2.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git b/src/main/resources/templates/Index.html a/src/main/resources/templates/Index.html new file mode 100644 index 0000000..32fac8a --- /dev/null +++ a/src/main/resources/templates/Index.html @@ -0,0 +1,139 @@ + + + + + +
+
+ + +
+ +
+
+ +
+
+ +
+ +
+
+ +
+ + +
+ + + + + + + + \ No newline at end of file diff --git b/src/test/java/com/example/demo/SNManageApplicationTest.java a/src/test/java/com/example/demo/SNManageApplicationTest.java new file mode 100644 index 0000000..547d344 --- /dev/null +++ a/src/test/java/com/example/demo/SNManageApplicationTest.java @@ -0,0 +1,33 @@ +package com.example.demo; + +import com.example.demo.service.SNService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.StringUtils; + +import java.io.File; +import java.util.Date; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +public class SNManageApplicationTest { + @Autowired + SNService snService; + + @Value("${SN.file.path}") + String SNFilePath; + + @Value("${SN.file.temp.path}") + String SNTempFilePath; + + @Test + public void test() throws Exception { + String encryptedSN = "c24x"; + snService.deleteSN(encryptedSN); + + } +}