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);
+
+ }
+}