├── .gitignore ├── des-be.iml ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── yyan │ │ ├── App.java │ │ ├── controller │ │ ├── BlockController.java │ │ ├── FileUploadController.java │ │ ├── HelloWorldController.java │ │ └── UserController.java │ │ ├── dao │ │ ├── BlockDao.java │ │ └── UserDao.java │ │ ├── filter │ │ └── FirstFilter.java │ │ ├── pojo │ │ ├── Block.java │ │ └── User.java │ │ ├── service │ │ ├── BlockService.java │ │ └── UserService.java │ │ ├── serviceImpl │ │ ├── BlockServiceImpl.java │ │ └── UserServiceImpl.java │ │ └── utils │ │ ├── BaseController.java │ │ ├── BaseServiceImpl.java │ │ ├── FileUtil.java │ │ ├── JwtUtil.java │ │ ├── ResultCodeEnum.java │ │ ├── ServiceException.java │ │ ├── SessionUtil.java │ │ └── StringUtil.java └── resources │ ├── application.properties │ ├── mapper │ ├── block.xml │ └── user.xml │ └── static │ ├── images │ ├── 18.jpeg │ ├── 22.jpg │ ├── 41a3146d-60de-4e22-8f28-fdd0282aa57f.jpeg │ ├── 76d3b075-f4ca-410c-92ce-67a60bb989c2.jpeg │ ├── 79fe5b58-17ed-4c4c-9b25-aef306494227.jpeg │ ├── a75b330d-aa49-4ed6-9c64-d9e8b9dddb6a.jpeg │ ├── c5d95b51-9004-469e-9181-1fb8e54684cc.jpeg │ ├── cdc6d6e7-065f-40be-a39f-105ed7585ce3.jpeg │ ├── d68dc7ea-6576-48f8-b504-c60af8085ae2.jpeg │ └── f43a8555-7a92-479c-92b1-f7cd90072677.jpeg │ └── uploadFile │ └── 2020 │ └── 04 │ └── 12 │ └── 963eaad5-4cf7-45fe-a12d-11124af2fac2.jpeg └── test └── java └── TestBlock.java /.gitignore: -------------------------------------------------------------------------------- 1 | /.vertx 2 | /target/ 3 | /.settings 4 | /.project 5 | /.idea 6 | /target 7 | /.gitee 8 | /classes 9 | .DS_Store 10 | /.DS_Store 11 | .idea 12 | /.idea -------------------------------------------------------------------------------- /des-be.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | com.yyan 9 | des-be 10 | 1.0-SNAPSHOT 11 | des-be 12 | 基于区块链电子存证系统 13 | war 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.1.13.RELEASE 21 | 22 | 23 | 24 | 25 | 26 | 27 | 1.8 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-aop 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-web 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | test 56 | 57 | 58 | org.junit.vintage 59 | junit-vintage-engine 60 | 61 | 62 | 63 | 64 | 65 | 66 | javax.servlet 67 | jstl 68 | 69 | 70 | 71 | org.apache.tomcat.embed 72 | tomcat-embed-jasper 73 | provided 74 | 75 | 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-starter-freemarker 80 | 81 | 82 | 83 | 84 | com.auth0 85 | java-jwt 86 | 3.3.0 87 | 88 | 89 | 90 | 91 | 92 | org.springframework.boot 93 | spring-boot-starter-thymeleaf 94 | 95 | 96 | 97 | 98 | org.mybatis.spring.boot 99 | mybatis-spring-boot-starter 100 | 2.1.1 101 | 102 | 103 | 104 | 105 | mysql 106 | mysql-connector-java 107 | 108 | 109 | 110 | com.alibaba 111 | druid 112 | 1.1.16 113 | 114 | 115 | 116 | 117 | 118 | org.springframework.boot 119 | spring-boot-devtools 120 | 121 | true 122 | 123 | 124 | 125 | 126 | 127 | org.springframework.boot 128 | spring-boot-starter-cache 129 | 130 | 131 | 132 | net.sf.ehcache 133 | ehcache 134 | 135 | 136 | 137 | 138 | org.projectlombok 139 | lombok 140 | true 141 | 142 | 143 | 144 | com.alibaba 145 | fastjson 146 | 1.2.49 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | org.springframework.boot 157 | spring-boot-maven-plugin 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/App.java: -------------------------------------------------------------------------------- 1 | package com.yyan; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.web.servlet.ServletComponentScan; 6 | 7 | // springboot 启动类 8 | @SpringBootApplication 9 | @ServletComponentScan // 在springboot 启动是会扫描@WebServlet,并将该类示例 10 | public class App { 11 | 12 | public static void main(String[] args) { 13 | // 执行启动器run 方法 14 | // 从当前包下进行扫描组件 15 | SpringApplication.run(App.class, args); 16 | 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/controller/BlockController.java: -------------------------------------------------------------------------------- 1 | package com.yyan.controller; 2 | 3 | import com.yyan.pojo.Block; 4 | import com.yyan.serviceImpl.BlockServiceImpl; 5 | import com.yyan.utils.BaseController; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | 12 | import java.util.Map; 13 | 14 | @Controller 15 | @RequestMapping("/api/block") 16 | public class BlockController extends BaseController { 17 | 18 | @Autowired 19 | private BlockServiceImpl blockService; 20 | 21 | /** 22 | *添加区块 23 | */ 24 | @RequestMapping("/insert") 25 | @ResponseBody 26 | public Map addBlock(@RequestBody Block block) { 27 | try { 28 | this.blockService.insertBlock(block); 29 | return this.buildSuccess(); 30 | } catch (Exception exp) { 31 | return this.buildError(exp.getMessage()); 32 | } 33 | } 34 | 35 | 36 | /** 37 | * 根据条件查询区块 38 | */ 39 | @RequestMapping("/select") 40 | @ResponseBody 41 | public Map getBlock(@RequestBody Map map) { 42 | try { 43 | return this.buildSuccess(this.blockService.selectListBlock(map)); 44 | } catch (Exception exp) { 45 | return this.buildError(exp.getMessage()); 46 | } 47 | } 48 | 49 | 50 | /** 51 | * 根据条件查询自己的区块 52 | */ 53 | @RequestMapping("/self/select") 54 | @ResponseBody 55 | public Map getBlockSelf(@RequestBody Map map) { 56 | try { 57 | return this.buildSuccess(this.blockService.selectListBlockSelf(map)); 58 | } catch (Exception exp) { 59 | System.out.println(exp); 60 | 61 | return this.buildError(exp.getMessage()); 62 | } 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/controller/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package com.yyan.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RequestParam; 5 | import org.springframework.web.bind.annotation.RestController; 6 | import org.springframework.web.multipart.MultipartFile; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.text.SimpleDateFormat; 12 | import java.util.Date; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.UUID; 16 | 17 | /** 18 | * springboot 文件上传 19 | */ 20 | // 该类下的方法的返回值会自动做 json 转换, 相当于 @ResponseBody + @Controller 21 | @RestController 22 | @RequestMapping("/api/file") 23 | 24 | public class FileUploadController { 25 | 26 | public final static String IMG_PATH_PREFIX = "static/images"; 27 | 28 | public static File getImgDirFile(String imgPath) { 29 | // 构建上传文件的存放 "文件夹" 路径s 30 | String fileDirPath = new String("src/main/resources/" + imgPath); 31 | File fileDir = new File(fileDirPath); 32 | if (!fileDir.exists()) { 33 | // 递归生成文件夹 34 | fileDir.mkdirs(); 35 | } 36 | return fileDir; 37 | } 38 | 39 | 40 | /** 41 | * 批量文件上传 42 | */ 43 | @RequestMapping("/upload") 44 | 45 | public Map fileUpload(HttpServletRequest request, MultipartFile fileName) { 46 | Map map = new HashMap(); 47 | if (fileName.isEmpty()) { 48 | map.put("msg", "上传失败,请选择文件"); 49 | } 50 | //获取文件名 51 | String fn = fileName.getOriginalFilename(); 52 | String prefix = fn.substring(fn.lastIndexOf("."));//文件后缀 53 | //新文件名 54 | String s = UUID.randomUUID().toString();//避免重复以UUID为文件名 55 | String filenas = s + prefix; 56 | // 存放上传图片的文件夹 57 | File fileDir = getImgDirFile(IMG_PATH_PREFIX); 58 | // 输出文件夹绝对路径 -- 这里的绝对路径是相当于当前项目的路径而不是“容器”路径 59 | String absolutePath = fileDir.getAbsolutePath(); 60 | File dest = new File(absolutePath + File.separator + filenas); 61 | try { 62 | fileName.transferTo(dest); 63 | //拼接地址 64 | String url = filenas; 65 | map.put("link", url); 66 | map.put("msg", "文件上传成功"); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | return map; 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/controller/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package com.yyan.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.ResponseBody; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | // 注入 bean 11 | @Controller 12 | public class HelloWorldController { 13 | 14 | // 将 url 与方法绑定 15 | @RequestMapping("/hello") 16 | // json 数据转换 17 | @ResponseBody 18 | public Map showHelloWorld() { 19 | Map map = new HashMap<>(); 20 | map.put("msg", "HELLO WORLD"); 21 | return map; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.yyan.controller; 2 | 3 | import com.yyan.pojo.User; 4 | import com.yyan.serviceImpl.UserServiceImpl; 5 | import com.yyan.utils.BaseController; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import java.util.Map; 15 | 16 | // 注入 bean 17 | @Controller 18 | @RequestMapping("/api/user") 19 | public class UserController extends BaseController { 20 | 21 | @Autowired 22 | private UserServiceImpl userService; 23 | 24 | /** 25 | * 添加用户 26 | */ 27 | @RequestMapping("/insert") 28 | @ResponseBody 29 | public Map addUser(@RequestBody User user) { 30 | try { 31 | this.userService.insertUser(user); 32 | return this.buildSuccess(); 33 | } catch (Exception exp) { 34 | return this.buildError(exp.getMessage()); 35 | } 36 | } 37 | 38 | 39 | /** 40 | * 用户登录 41 | */ 42 | @RequestMapping("/login") 43 | @ResponseBody 44 | public Map selectUser(HttpServletRequest request,@RequestBody User user) { 45 | try { 46 | Map map = this.userService.login(user.getEmail(), user.getPassword()); 47 | request.getSession().setAttribute("userId", map.get("id")); 48 | return this.buildSuccess(map); 49 | } catch (Exception exp) { 50 | return this.buildError(exp.getMessage()); 51 | } 52 | } 53 | 54 | /** 55 | * 用户登出 56 | */ 57 | @RequestMapping("/logout") 58 | @ResponseBody 59 | public Map logout() { 60 | try { 61 | 62 | // todo 清空session 63 | return this.buildSuccess(); 64 | } catch (Exception exp) { 65 | return this.buildError(exp.getMessage()); 66 | } 67 | } 68 | 69 | 70 | /** 71 | * 添加用户 72 | */ 73 | @RequestMapping("/update") 74 | @ResponseBody 75 | public Map updateUser(@RequestBody User user) { 76 | try { 77 | this.userService.updateUser(user); 78 | return this.buildSuccess(); 79 | } catch (Exception exp) { 80 | return this.buildError(exp.getMessage()); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/dao/BlockDao.java: -------------------------------------------------------------------------------- 1 | package com.yyan.dao; 2 | 3 | import com.yyan.pojo.Block; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | @Mapper 10 | public interface BlockDao { 11 | 12 | // 添加区块 13 | void insertBlock(Block block); 14 | 15 | // 查询区块 16 | List selectListBlock(Map map); 17 | Integer countListBlock(Map map); // 查询区块数量 18 | 19 | 20 | // 获取最后一行数据 21 | Block selectEndBlock(); 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.yyan.dao; 2 | 3 | import com.yyan.pojo.User; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | import java.util.Map; 7 | 8 | @Mapper 9 | public interface UserDao { 10 | 11 | void insertUser(User user); 12 | 13 | void updateUser(User user); 14 | 15 | User login(Map map); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/filter/FirstFilter.java: -------------------------------------------------------------------------------- 1 | package com.yyan.filter; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.yyan.utils.JwtUtil; 5 | import com.yyan.utils.ResultCodeEnum; 6 | 7 | 8 | import javax.servlet.*; 9 | import javax.servlet.annotation.WebFilter; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.io.PrintWriter; 14 | import java.util.Arrays; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | @WebFilter(filterName = "FirstFilter", urlPatterns = "/*") 19 | public class FirstFilter implements Filter { 20 | 21 | @Override 22 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 23 | System.out.println("进入 filter " + request); 24 | 25 | 26 | HttpServletRequest req = (HttpServletRequest) request; 27 | // HttpServletResponse rep = (HttpServletResponse) response; 28 | // 29 | // //设置允许跨域的配置 30 | // // 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP) 31 | // rep.setHeader("Access-Control-Allow-Origin", "*"); 32 | // // 允许的访问方法 33 | // rep.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); 34 | // // Access-Control-Max-Age 用于 CORS 相关配置的缓存 35 | // rep.setHeader("Access-Control-Max-Age", "3600"); 36 | // rep.setHeader("Access-Control-Allow-Headers", "token,Origin, X-Requested-With, Content-Type, Accept"); 37 | // 38 | // 39 | // response.setCharacterEncoding("UTF-8"); 40 | // response.setContentType("application/json; charset=utf-8"); 41 | // 42 | // // todo 不就进行token校验白名单 43 | // String[] urls = { 44 | // "/hello", 45 | // "/images/", 46 | // "/api/user/login", 47 | // "/api/file/upload", 48 | // "/api/user/insert", 49 | // "/api/block/select", 50 | // }; 51 | // 52 | // String currentUrl = req.getRequestURI().split("\\?")[0]; 53 | // 54 | // for(String url:urls ){// 过滤非验证路由 55 | // if(currentUrl.startsWith(url)){ 56 | // chain.doFilter(request, response); 57 | // return; 58 | // } 59 | // } 60 | // 61 | // String token = req.getHeader("Authorization");// 获取 token 62 | // 63 | // Boolean status = JwtUtil.verify(token); 64 | // 65 | // if (null == token || token.isEmpty() || !status) { // token 校验失败 66 | // Map map = new HashMap(); 67 | // ResultCodeEnum resultCode = ResultCodeEnum.USER_ERROR; 68 | // map.put("code", Integer.parseInt(resultCode.getCode())); 69 | // map.put("info", resultCode.getMessage()); 70 | // PrintWriter writer = response.getWriter(); 71 | // writer.write(JSON.toJSONString(map)); 72 | // return; 73 | // } 74 | 75 | chain.doFilter(request, response); // token 校验 success 76 | 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/pojo/Block.java: -------------------------------------------------------------------------------- 1 | package com.yyan.pojo; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | @Data 8 | public class Block { 9 | 10 | public String id; // 区块 id 11 | public String userId; // 创建人 12 | private String userName; // 加密文件路径 13 | public String preHash; // 前节点hash 14 | private String fileUrl; // 加密文件路径 15 | private long timeStamp; //时间搓 1/1/1970. 16 | private int nonce; // 随机数 17 | public String hash; // 当前节点hash 18 | public String category; // 当前节点hash 19 | public Integer height; // 区块高度 20 | 21 | private Date createTime; // 创建时间 22 | private Date updateTime; // 修改时间 23 | private User user;// 区块创建人 24 | 25 | 26 | // /** 27 | // * 初始化区块 28 | // * 29 | // * @param data 30 | // * @param preHash 31 | // */ 32 | // public Block(String data, String preHash,String userId,Integer height) { 33 | // this.userId = userId; 34 | // this.height = height; 35 | // this.fileUrl = data; 36 | // this.preHash = preHash; 37 | // this.timeStamp = new Date().getTime(); 38 | // this.hash = calculateHash(); // 当前节点hash 39 | // } 40 | // 41 | // 42 | // /** 43 | // * 计算hash值 44 | // * 45 | // * @return hash 46 | // */ 47 | // public String calculateHash() { 48 | // String calculatedhash = StringUtil.applySha256( 49 | // preHash + 50 | // Long.toString(timeStamp) + 51 | // Integer.toString(nonce) + 52 | // fileUrl 53 | // ); 54 | // return calculatedhash; 55 | // } 56 | // 57 | // 58 | // /** 59 | // * 工作量证明 60 | // */ 61 | // 62 | // public void mineBlock(int difficulty) { 63 | // String target = new String(new char[difficulty]).replace('\0', '0'); //Create a string with difficulty * "0" 64 | // while (!hash.substring(0, difficulty).equals(target)) { 65 | // nonce++; 66 | // hash = calculateHash(); 67 | // } 68 | // System.out.println("Block Mined!!! : " + hash); 69 | // } 70 | } -------------------------------------------------------------------------------- /src/main/java/com/yyan/pojo/User.java: -------------------------------------------------------------------------------- 1 | package com.yyan.pojo; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | @Data 8 | public class User { 9 | private String id; 10 | private String phone; // 用户手机号 11 | private String email; // 用户邮箱 12 | private String name; // 用户名 13 | private String password; // 登录密码 14 | private Date createTime; // 创建时间 15 | private Date updateTime; // 修改时间 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/service/BlockService.java: -------------------------------------------------------------------------------- 1 | package com.yyan.service; 2 | 3 | import com.yyan.pojo.Block; 4 | 5 | import java.io.FileNotFoundException; 6 | import java.util.Map; 7 | 8 | public interface BlockService { 9 | 10 | 11 | // 添加区块 12 | void insertBlock(Block block) throws FileNotFoundException; 13 | 14 | // 查询区块 15 | Map selectListBlock(Map map); // 查询区块 16 | 17 | // 查询自己的区块 18 | Map selectListBlockSelf(Map map); // 查询区块 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.yyan.service; 2 | 3 | import com.yyan.pojo.User; 4 | 5 | import java.util.Map; 6 | 7 | public interface UserService { 8 | 9 | void insertUser(User user); 10 | 11 | void updateUser(User user); 12 | 13 | Map login(String email, String password); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/serviceImpl/BlockServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.yyan.serviceImpl; 2 | 3 | import com.yyan.dao.BlockDao; 4 | import com.yyan.pojo.Block; 5 | import com.yyan.service.BlockService; 6 | import com.yyan.utils.BaseServiceImpl; 7 | import com.yyan.utils.FileUtil; 8 | import com.yyan.utils.StringUtil; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.Date; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @Service 17 | public class BlockServiceImpl extends BaseServiceImpl implements BlockService { 18 | 19 | public static int difficulty = 2; // 挖矿难度系数 5 20 | public final static String IMG_PATH_PREFIX = "src/main/resources/static/images/"; 21 | 22 | @Autowired 23 | private BlockDao blockDao; 24 | 25 | @Override 26 | public void insertBlock(Block block) { 27 | 28 | // 获取主链 29 | Block endBlock = blockDao.selectEndBlock(); 30 | // 用户 id 31 | String userId = getUserIdToken(); 32 | block.setUserId(userId); 33 | 34 | if (endBlock == null) { // 创世区块 35 | block.setHeight(0); 36 | block.setPreHash("0"); 37 | } else { 38 | block.setHeight(endBlock.getHeight() + 1); 39 | block.setPreHash(endBlock.getHash()); 40 | } 41 | 42 | // 设置访问路径 43 | String filePath = new String(IMG_PATH_PREFIX + block.getFileUrl()); 44 | 45 | block.setTimeStamp((new Date()).getTime()); 46 | 47 | String target = new String(new char[difficulty]).replace('\0', '0'); //Create a string with difficulty * "0" 48 | Integer nonce = 0; 49 | String base64File = FileUtil.encryptToBase64(filePath); 50 | String hash = calHash(block, base64File); 51 | 52 | // 工作量证明 挖矿 53 | while (!hash.substring(0, difficulty).equals(target)) { 54 | nonce++; 55 | block.setNonce(nonce); 56 | hash = calHash(block, base64File); 57 | System.out.println("hash=====" + hash); 58 | } 59 | block.setHash(hash); 60 | // 添加区块 61 | this.blockDao.insertBlock(block); 62 | 63 | } 64 | 65 | 66 | /** 67 | * 计算hash值 68 | * 69 | * @return hash 70 | */ 71 | public String calHash(Block block, String base64File) { 72 | 73 | return StringUtil.applySha256( 74 | block.getPreHash() + 75 | Long.toString(block.getTimeStamp()) + 76 | Integer.toString(block.getNonce()) + 77 | base64File 78 | 79 | ); 80 | 81 | } 82 | 83 | 84 | @Override 85 | public Map selectListBlock(Map map) { 86 | 87 | List newList = this.blockDao.selectListBlock(checkPageSize(map)); 88 | 89 | Integer count = this.blockDao.countListBlock(map); 90 | return this.queryListSuccess(newList, count, map); //查询成功 91 | 92 | } 93 | 94 | @Override 95 | public Map selectListBlockSelf(Map map) { 96 | map.put("userId", getUserIdToken()); //添加用户id 97 | 98 | List newList = this.blockDao.selectListBlock(checkPageSize(map)); 99 | 100 | Integer count = this.blockDao.countListBlock(map); 101 | return this.queryListSuccess(newList, count, map); //查询成功 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/serviceImpl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.yyan.serviceImpl; 2 | 3 | import com.yyan.dao.UserDao; 4 | import com.yyan.pojo.User; 5 | import com.yyan.service.UserService; 6 | import com.yyan.utils.BaseServiceImpl; 7 | import com.yyan.utils.JwtUtil; 8 | import com.yyan.utils.StringUtil; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | @Service 16 | public class UserServiceImpl extends BaseServiceImpl implements UserService { 17 | 18 | @Autowired 19 | private UserDao userDao; 20 | 21 | /** 22 | * 注册用户 23 | * 24 | * @param user 25 | */ 26 | @Override 27 | public void insertUser(User user) { 28 | user.setPassword(StringUtil.md5Code(user.getPassword())); //对密码进行 md5 29 | userDao.insertUser(user); 30 | } 31 | 32 | /** 33 | * 更新用户密码 34 | * 35 | * @param user 36 | */ 37 | @Override 38 | public void updateUser(User user) { 39 | // 用户 id 40 | String userId = getUserIdToken(); 41 | user.setId(userId); 42 | user.setPassword(StringUtil.md5Code(user.getPassword())); //对密码进行 md5 43 | userDao.updateUser(user); 44 | } 45 | 46 | /** 47 | * 返回登录人信息 48 | * 49 | * @param email 50 | * @param pass 51 | * @return 52 | */ 53 | @Override 54 | public Map login(String email, String pass) { 55 | String password = StringUtil.md5Code(pass); //对密码进行 md5 56 | Map map = new HashMap(); 57 | map.put("email", email); 58 | map.put("password", password); 59 | // 通过邮箱查询数据库 60 | User user = userDao.login(map); 61 | Map resultMap = new HashMap(); 62 | resultMap.put("id", user.getId()); 63 | resultMap.put("name", user.getName()); 64 | 65 | // 生成token 66 | String token = JwtUtil.sign(user.getEmail(), user.getId()); 67 | resultMap.put("token", token); 68 | 69 | return resultMap; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils; 2 | 3 | 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class BaseController { 8 | 9 | 10 | // 成功 11 | public Map buildSuccess(Object data) { 12 | Map map = new HashMap(); 13 | ResultCodeEnum resultCode = ResultCodeEnum.SUCCESS; 14 | map.put("code", Integer.parseInt(resultCode.getCode())); 15 | map.put("info", resultCode.getMessage()); 16 | map.put("data", data); 17 | return map; 18 | } 19 | 20 | // 成功 21 | public Map buildSuccess() { 22 | return this.buildSuccess(null); 23 | } 24 | 25 | // 失败 26 | public Map buildError(String message) { 27 | Map map = new HashMap(); 28 | ResultCodeEnum resultCode = ResultCodeEnum.FAILED; 29 | map.put("code", Integer.parseInt(resultCode.getCode())); 30 | if (message == null || message.isEmpty()) { 31 | map.put("info", resultCode.getMessage()); 32 | } else { 33 | map.put("info", message); 34 | } 35 | return map; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/BaseServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils; 2 | 3 | 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.cglib.beans.BeanMap; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.context.request.ServletRequestAttributes; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpSession; 11 | import java.util.*; 12 | 13 | 14 | public class BaseServiceImpl { 15 | 16 | 17 | @Autowired 18 | private HttpSession session; 19 | 20 | @Autowired 21 | private HttpServletRequest request; 22 | 23 | public String getUserIdToken() { 24 | String token = request.getHeader("Authorization");// 获取 token 25 | return JwtUtil.getUserId(token); 26 | } 27 | 28 | 29 | /** 30 | * 获取用户 id 31 | * 32 | * @return 33 | */ 34 | public String getUserIdSession() { 35 | return (String) session.getAttribute("userId"); 36 | } 37 | 38 | 39 | // 查询成功数据组装 40 | public Map queryListSuccess(Object data, Integer count, Map param) { 41 | Map map = new HashMap<>(); 42 | map.put("rows", data); 43 | map.put("pageNumber", param.get("pageIndex")); 44 | map.put("pageSize", param.get("size")); 45 | map.put("total", count); 46 | return map; 47 | } 48 | 49 | // 去掉实体中没有必要的字段 50 | public List queryListClearField(List list, String[] arr) { 51 | List> newList = new ArrayList<>(); 52 | for (Object object : list) { 53 | Map map = new HashMap<>(); 54 | map.putAll(BeanMap.create(object)); 55 | for (String key : arr) { 56 | map.remove(key);// 去掉不必要的字段 57 | } 58 | newList.add(map); 59 | } 60 | return newList; 61 | } 62 | 63 | 64 | /** 65 | * 批量插入数据,为数据添加 id,createTime,updateTime 66 | * 67 | * @param list 68 | * @return 69 | */ 70 | public List insertListBefore(List list) { 71 | List> newList = new ArrayList<>(); 72 | for (Object object : list) { 73 | Map map = new HashMap<>(); 74 | String id = UUID.randomUUID().toString(); 75 | System.out.println("id" + id); 76 | map.put("id", id); // 添加 id 77 | map.put("updateTime", new Date()); // 添加创建时间 78 | map.put("createTime", new Date()); // 添加修改时间 79 | newList.add(map); 80 | } 81 | return newList; 82 | 83 | } 84 | 85 | 86 | public Map checkPageSize(Map map) { 87 | 88 | Integer size = map.get("size") != null ? (Integer) map.get("size") : 10; 89 | Integer pageIndex = map.get("pageIndex") != null ? (Integer) map.get("pageIndex") : 0; 90 | map.put("size", size); 91 | map.put("pageIndex", pageIndex); 92 | return map; 93 | } 94 | 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.math.BigInteger; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.security.MessageDigest; 9 | import java.util.Base64; 10 | 11 | public class FileUtil { 12 | 13 | /** 14 | * java获取文件的SHA-256值 15 | * 16 | * @param fis 输入流 17 | * @return 18 | */ 19 | public static String fileHashCode(FileInputStream fis) { 20 | try { 21 | //SHA-256,如果想使用SHA-1或MD5,则传入SHA-1,MD5 22 | MessageDigest md = MessageDigest.getInstance("SHA-256"); 23 | 24 | //分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。 25 | byte[] buffer = new byte[1024]; 26 | int length = -1; 27 | while ((length = fis.read(buffer, 0, 1024)) != -1) { 28 | md.update(buffer, 0, length); 29 | } 30 | fis.close(); 31 | //转换并返回包含16个元素字节数组,返回数值范围为-128到127 32 | byte[] bytes = md.digest(); 33 | BigInteger bigInt = new BigInteger(1, bytes);//1代表绝对值 34 | return bigInt.toString(16);//转换为16进制 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | return ""; 38 | } 39 | } 40 | 41 | 42 | public static String encryptToBase64(String filePath) { 43 | if (filePath == null) { 44 | return null; 45 | } 46 | try { 47 | byte[] b = Files.readAllBytes(Paths.get(filePath)); 48 | return Base64.getEncoder().encodeToString(b); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | 53 | return null; 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/JwtUtil.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils; 2 | 3 | import com.auth0.jwt.JWT; 4 | import com.auth0.jwt.JWTVerifier; 5 | import com.auth0.jwt.algorithms.Algorithm; 6 | import com.auth0.jwt.exceptions.JWTDecodeException; 7 | import com.auth0.jwt.interfaces.DecodedJWT; 8 | 9 | import java.io.UnsupportedEncodingException; 10 | import java.util.Date; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | 15 | public class JwtUtil { 16 | 17 | 18 | /** 19 | * 过期时间一天, 20 | * TODO 正式运行时修改为15分钟 21 | */ 22 | private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; 23 | /** 24 | * token私钥 25 | */ 26 | private static final String TOKEN_SECRET = "f26e587c28064d0e855e72c0a6a0e618"; 27 | 28 | /** 29 | * 生成签名,15min后过期 30 | * 31 | * @param email 邮箱 32 | * @return 加密的token 33 | */ 34 | public static String sign(String email, String id) { 35 | try { 36 | // 过期时间 37 | Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); 38 | // 私钥及加密算法 39 | Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); 40 | // 设置头部信息 41 | Map header = new HashMap<>(2); 42 | header.put("typ", "JWT"); 43 | header.put("alg", "HS256"); 44 | // 附带username,userId信息,生成签名 45 | return JWT.create() 46 | .withHeader(header) 47 | .withClaim("id", id) 48 | .withClaim("email", email) 49 | .withExpiresAt(date) 50 | .sign(algorithm); 51 | } catch (UnsupportedEncodingException e) { 52 | return null; 53 | } 54 | } 55 | 56 | 57 | /** 58 | * 获取登陆用户ID 59 | * 60 | * @param token 61 | * @return 62 | */ 63 | public static String getUserId(String token) { 64 | try { 65 | DecodedJWT jwt = JWT.decode(token); 66 | return jwt.getClaim("id").asString(); 67 | } catch (JWTDecodeException e) { 68 | return null; 69 | } 70 | } 71 | 72 | 73 | /** 74 | * 获得token中的信息无需secret解密也能获得 75 | * 76 | * @return token中包含的用户名 77 | */ 78 | public static String getEmail(String token) { 79 | try { 80 | DecodedJWT jwt = JWT.decode(token); 81 | return jwt.getClaim("email").asString(); 82 | } catch (JWTDecodeException e) { 83 | return null; 84 | } 85 | } 86 | 87 | 88 | /** 89 | * 校验token是否正确 90 | * 91 | * @param token 密钥 92 | * @return 是否正确 93 | */ 94 | public static boolean verify(String token) { 95 | try { 96 | Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); 97 | JWTVerifier verifier = JWT.require(algorithm) 98 | .build(); 99 | DecodedJWT jwt = verifier.verify(token); 100 | return true; 101 | } catch (Exception exception) { 102 | return false; 103 | } 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/ResultCodeEnum.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 系统返回状态值编码 8 | * Created by rl on 2016/11/29 0001. 9 | */ 10 | 11 | public enum ResultCodeEnum { 12 | 13 | //通用技术相关 14 | SUCCESS("200", "操作成功"), 15 | FAILED("-1", "请求失败"), 16 | AUTH_FAIL("-2", "请求验证失败!"), 17 | 18 | PARAM_ERROR("-4", "缺少参数!"), 19 | USER_ERROR("-5", "未登录或登录信息过期!"), 20 | 21 | //App错误码 22 | /** 23 | * 系统级错误码 1 - 200 24 | */ 25 | APP_REQUEST_ERROR("101", "网络不给力,请稍后~"),//网络延时、数据异常、代码报错、未请求到结果、请求超时等异常状态 26 | APP_IP_ERROR("102", "您的IP已被封禁,如有疑问,请联系管理员"), 27 | APP_ACCOUNT_ERROR("103", "您的账号已被封禁,如有疑问,请联系管理员"), 28 | ACCOUNT_POWER_ERROR("104", "无权限访问此节点"), 29 | /** 30 | * 业务级错误码 APP不需要验证 - 只提示 501 - 700 31 | */ 32 | APP_REGISTER_PHONE_ISNOTNULL("501", "手机号已注册"),//APP登陆-手机号不存在 33 | APP_LOGIN_PHONE_ISNULL("502", "账号或密码不正确"),//APP登陆-手机号不存在 34 | APP_SMS_ERROR("503", "验证码错误"),//APP登陆-手机号不存在 35 | APP_REGISTERCODE_ERROR("504", "邀请码不正确"),//APP注册-邀请码不正确 36 | APP_SMS_SEND_ERROR("505", "验证码发送失败,请重试"), 37 | APP_PHONE_ERROR("506", "手机号格式不正确,请重新输入"), 38 | APP_lOGIN_USER_ERROR("507", "账号异常禁止登陆"), 39 | APP_SMS_SENDMANY_ERROR("508", "发送超限,明天再试!"), 40 | APP_USER_IDCARD_ERROR("509", "该身份证号已被绑定"), 41 | APP_USER_IDCARD_OTHERERROR("510", ""),//身份证号其他错误 42 | APP_USER_WORD_ERROE("513", "昵称不合法"), 43 | APP_USER_IDCARD_JyzxUtilERROR("514", "验证身份证失败"),//身份证号其他错误 44 | APP_GOODS_ACTIVITY_ERROR("520", "本期活动已结束"), 45 | APP_GOODS_ACTIVITY_TIME_ERROR("521", "活动稍后开始"), 46 | APP_GOODS_ACTIVITY_OVER_ERROR("522", "商品已被抢完,手速慢了点"), 47 | APP_AUTH_NAME_ERROR("523", "请先进行实名认证"), 48 | APP_AUTH_ADDRESS_ERROR("524", "请先填写收货地址"), 49 | APP_HANGSALE_STATE_ERROR("530", "当前挂拍已结束"), 50 | APP_ALIPAY_LOGIN_ERROR("537", "支付宝绑定失败"), 51 | APP_ALIPAY_TRANSFERACCOUNTS_ERROR("538", "支付宝转账失败"), 52 | APP_ALIPAY_AUTHORIZATION_ERROR("539", "支付宝授权失败"), 53 | APP_ALIPAY_USER_ERROR("540", "该支付宝账号已被绑定"), 54 | APP_ALIPAY_CREATEACTIVUTY_ERROR("541", "创建现金活动失败"), 55 | APP_ALIPAY_PUTFORWARD_ERROR("542", "提现失败"), 56 | APP_ALIPAY_NO_BOUND_ERROR("544", "请先绑定支付宝"), 57 | 58 | /** 59 | * 业务级错误码 APP需要验证 - 不提示 801 - 999 60 | */ 61 | APP_USER_NOIDCARDS_ERROR("805", "未绑定身份证"), 62 | APP_USER_NOALIPAY_ERROR("806", "未绑定支付宝"), 63 | APP_REGISTER_PHONE_ISNULL("801", "手机号未注册"), 64 | APP_lOGIN_TOKEN_ISNULL("802", "登陆信息超时,请重新登陆"), 65 | APP_lOGIN_TOKEN_UPDATE("803", "你的账号在其他设备上登陆"), 66 | APP_EDITION_TO_UPDATE("804", "发现新版本,立即体验!");//APP版本更新 67 | 68 | 69 | private String code; 70 | private String message; 71 | 72 | private ResultCodeEnum(String code, String message) { 73 | this.code = code; 74 | this.message = message; 75 | } 76 | 77 | private static final Map interToEnum = new HashMap(); 78 | 79 | static { 80 | for (ResultCodeEnum type : ResultCodeEnum.values()) { 81 | interToEnum.put(type.getCode(), type); 82 | } 83 | } 84 | 85 | public String getCode() { 86 | return code; 87 | } 88 | 89 | public void setCode(String code) { 90 | this.code = code; 91 | } 92 | 93 | public String getMessage() { 94 | return message; 95 | } 96 | 97 | public void setMessage(String message) { 98 | this.message = message; 99 | } 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/ServiceException.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils;//package com.yyan.utils; 2 | // 3 | //public class ServiceException extends RuntimeException { 4 | // 5 | // private Integer code; 6 | // private String desc; 7 | // 8 | // public ServiceException(Integer code, String desc) { 9 | // super(desc); 10 | // this.code = code; 11 | // this.desc = desc; 12 | // } 13 | // 14 | // public Integer getCode() { 15 | // return code; 16 | // } 17 | // 18 | // public void setCode(Integer code) { 19 | // this.code = code; 20 | // } 21 | // 22 | // public String getDesc() { 23 | // return desc; 24 | // } 25 | // 26 | // public void setDesc(String desc) { 27 | // this.desc = desc; 28 | // } 29 | //} -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/SessionUtil.java: -------------------------------------------------------------------------------- 1 | //package com.yyan.utils; 2 | // 3 | //import org.springframework.beans.factory.annotation.Autowired; 4 | // 5 | //import javax.servlet.http.HttpSession; 6 | // 7 | //public class SessionUtil { 8 | // @Autowired 9 | // private HttpSession session; 10 | // 11 | // /** 12 | // * 获取用户 id 13 | // * 14 | // * @return 15 | // */ 16 | // public String getUserIdSession() { 17 | // return (String) session.getAttribute("userId"); 18 | // } 19 | // 20 | // 21 | //} 22 | -------------------------------------------------------------------------------- /src/main/java/com/yyan/utils/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.yyan.utils; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.math.BigInteger; 6 | import java.security.MessageDigest; 7 | 8 | public class StringUtil { 9 | 10 | /** 11 | * 创建数字签名 12 | *

13 | * Java方式可以实现的加密方式有很多,例如BASE、MD、RSA、SHA等等, 14 | * 我在这里选用了SHA256这种加密方式,SHA(Secure Hash Algorithm) 15 | * 安全散列算法,这种算法的特点是数据的少量更改会在Hash值中产生不可预知的大量更改, 16 | * hash值用作表示大量数据的固定大小的唯一值,而SHA256算法的hash值大小为256位。 17 | * 之所以选用SHA256是因为它的大小正合适,一方面产生重复hash值的可能性很小, 18 | * 另一方面在区块链实际应用过程中,有可能会产生大量的区块,而使得信息量很大 19 | * ,那么256位的大小就比较恰当了 20 | * 21 | * @param input 22 | * @return 23 | */ 24 | 25 | public static String applySha256(String input) { 26 | try { 27 | MessageDigest digest = MessageDigest.getInstance("SHA-256"); 28 | //将sha256应用于我们的输入 29 | byte[] hash = digest.digest(input.getBytes("UTF-8")); 30 | StringBuffer hexString = new StringBuffer(); // 它将包含hash作为hexidecima 31 | 32 | for (int i = 0; i < hash.length; i++) { 33 | String hex = Integer.toHexString(0xff & hash[i]); 34 | if (hex.length() == 1) hexString.append('0'); 35 | hexString.append(hex); 36 | } 37 | return hexString.toString(); 38 | } catch (Exception e) { 39 | throw new RuntimeException(e); 40 | } 41 | } 42 | 43 | 44 | /** 45 | * 对字符串进行md5 46 | * @param input 47 | * @return 48 | */ 49 | public static String md5Code(String input) { 50 | try { 51 | MessageDigest digest = MessageDigest.getInstance("MD5"); 52 | //将sha256应用于我们的输入 53 | byte[] hash = digest.digest(input.getBytes("UTF-8")); 54 | StringBuffer hexString = new StringBuffer(); // 它将包含hash作为hexidecima 55 | 56 | for (int i = 0; i < hash.length; i++) { 57 | String hex = Integer.toHexString(0xff & hash[i]); 58 | if (hex.length() == 1) hexString.append('0'); 59 | hexString.append(hex); 60 | } 61 | return hexString.toString(); 62 | } catch (Exception e) { 63 | throw new RuntimeException(e); 64 | } 65 | } 66 | 67 | 68 | 69 | 70 | // public static void main(String[] args) { 71 | // try { 72 | // //此处我测试的是我本机jdk源码文件的MD5值 73 | // String filePath = "C:\\Program Files\\Java\\jdk1.7.0_45\\src.zip"; 74 | // FileInputStream fis = new FileInputStream(filePath); 75 | // String md5Hashcode = fileHashCode(fis); 76 | // 77 | // System.out.println(md5Hashcode + ":文件的md5值"); 78 | // 79 | // //System.out.println(-100 & 0xff); 80 | // } catch (FileNotFoundException e) { 81 | // e.printStackTrace(); 82 | // } 83 | // } 84 | // 85 | 86 | 87 | 88 | 89 | /** 90 | * java获取文件的SHA-256值 91 | * 92 | * @param fis 输入流 93 | * @return 94 | */ 95 | 96 | public static String fileHashCode(FileInputStream fis) { 97 | try { 98 | //SHA-256,如果想使用SHA-1或MD5,则传入SHA-1,MD5 99 | MessageDigest md = MessageDigest.getInstance("SHA-256"); 100 | 101 | //分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。 102 | byte[] buffer = new byte[1024]; 103 | int length = -1; 104 | while ((length = fis.read(buffer, 0, 1024)) != -1) { 105 | md.update(buffer, 0, length); 106 | } 107 | fis.close(); 108 | //转换并返回包含16个元素字节数组,返回数值范围为-128到127 109 | byte[] bytes = md.digest(); 110 | BigInteger bigInt = new BigInteger(1, bytes);//1代表绝对值 111 | return bigInt.toString(16);//转换为16进制 112 | } catch (Exception e) { 113 | e.printStackTrace(); 114 | return ""; 115 | } 116 | } 117 | 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # 单个文件大小 2 | spring.servlet.multipart.max-file-size=10MB 3 | # 总文件大小 4 | spring.servlet.multipart.max-request-size=50MB 5 | 6 | # 数据库相关 7 | #数据库驱动 8 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 9 | spring.datasource.url=jdbc:mysql://localhost:3306/des?allowMultiQueries=true 10 | #账号 11 | spring.datasource.username=root 12 | #密码 13 | spring.datasource.password=ld20110702 14 | # 数据库连接池 15 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 16 | 17 | # mybatis 配置 18 | # 扫描路径 19 | mybatis.mapper-locations=classpath:mapper/*.xml 20 | # 打印 mybatis 执行的 SQL 语句 21 | mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl 22 | # 包别名 23 | mybatis.type-aliases-package=com.yyan.pojo 24 | 25 | # JPA 相关 26 | # 第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构 27 | spring.jpa.hibernate.ddl-auto=update 28 | # 控制台输出 sql 语句 29 | spring.jpa.show-sql=true 30 | 31 | spring.mvc.async.request-timeout=2000s 32 | 33 | spring.jackson.date-format=yyyy-MM-dd HH:mm:ss 34 | spring.jackson.time-zone=GMT+8 35 | 36 | -------------------------------------------------------------------------------- /src/main/resources/mapper/block.xml: -------------------------------------------------------------------------------- 1 | insert into block( id, userId,preHash,fileUrl,timeStamp,category,nonce,hash,height,createTime,updateTime ) values (uuid(), #{userId},#{preHash},#{fileUrl},#{timeStamp},#{category},#{nonce},#{hash},#{height}, now(), now()) and userId= #{userId} and id=#{id} and category=#{category} and hash=#{hash} -------------------------------------------------------------------------------- /src/main/resources/mapper/user.xml: -------------------------------------------------------------------------------- 1 | insert into user(id, phone,password,email,name,createTime,updateTime) values (uuid(), #{phone},#{password},#{email},#{name}, now(), now()) update user email=#{email}, password=#{password}, updateTime=now() where 1=1 and id = #{id} -------------------------------------------------------------------------------- /src/main/resources/static/images/18.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/18.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/22.jpg -------------------------------------------------------------------------------- /src/main/resources/static/images/41a3146d-60de-4e22-8f28-fdd0282aa57f.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/41a3146d-60de-4e22-8f28-fdd0282aa57f.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/76d3b075-f4ca-410c-92ce-67a60bb989c2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/76d3b075-f4ca-410c-92ce-67a60bb989c2.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/79fe5b58-17ed-4c4c-9b25-aef306494227.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/79fe5b58-17ed-4c4c-9b25-aef306494227.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/a75b330d-aa49-4ed6-9c64-d9e8b9dddb6a.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/a75b330d-aa49-4ed6-9c64-d9e8b9dddb6a.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/c5d95b51-9004-469e-9181-1fb8e54684cc.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/c5d95b51-9004-469e-9181-1fb8e54684cc.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/cdc6d6e7-065f-40be-a39f-105ed7585ce3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/cdc6d6e7-065f-40be-a39f-105ed7585ce3.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/d68dc7ea-6576-48f8-b504-c60af8085ae2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/d68dc7ea-6576-48f8-b504-c60af8085ae2.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/images/f43a8555-7a92-479c-92b1-f7cd90072677.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/images/f43a8555-7a92-479c-92b1-f7cd90072677.jpeg -------------------------------------------------------------------------------- /src/main/resources/static/uploadFile/2020/04/12/963eaad5-4cf7-45fe-a12d-11124af2fac2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranyanchuan/des-be/673317cab41826ea4abc51045f746459ea0883c8/src/main/resources/static/uploadFile/2020/04/12/963eaad5-4cf7-45fe-a12d-11124af2fac2.jpeg -------------------------------------------------------------------------------- /src/test/java/TestBlock.java: -------------------------------------------------------------------------------- 1 | //import com.alibaba.fastjson.JSONObject; 2 | //import com.yyan.App; 3 | //import com.yyan.pojo.Block; 4 | //import org.junit.Test; 5 | //import org.junit.runner.RunWith; 6 | //import org.springframework.boot.test.context.SpringBootTest; 7 | //import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | // 9 | //import java.util.ArrayList; 10 | // 11 | // 12 | //@RunWith(SpringJUnit4ClassRunner.class) 13 | //@SpringBootTest(classes = {App.class}) 14 | //public class TestBlock { 15 | // 16 | // 17 | // public static ArrayList blockchain = new ArrayList<>(); 18 | // public static int difficulty = 5; 19 | // 20 | // @Test 21 | // public void blockchainTest() { 22 | // //添加我们的区块到主链上 23 | //// blockchain.add(new Block("这是创世区块", "0")); 24 | //// System.out.println("正在挖掘创世区块... "); 25 | //// blockchain.get(0).mineBlock(difficulty); 26 | //// 27 | //// blockchain.add(new Block("这是第二个区块", blockchain.get(blockchain.size() - 1).hash)); 28 | //// System.out.println("正在挖掘第二个区块... ... "); 29 | //// blockchain.get(1).mineBlock(difficulty); 30 | //// 31 | //// blockchain.add(new Block("这是第三个区块", blockchain.get(blockchain.size() - 1).hash)); 32 | //// System.out.println("正在挖掘第三个区块... ... "); 33 | //// 34 | //// blockchain.get(2).mineBlock(difficulty); 35 | //// 36 | //// System.out.println("\n主链校验: " + isChainValid()); 37 | //// 38 | //// String blockchainJson = JSONObject.toJSONString(blockchain); 39 | //// System.out.println("\n区块链: "); 40 | //// System.out.println(blockchainJson); 41 | // } 42 | // 43 | // 44 | // /** 45 | // * 检查区块链的完整性:目的是循环区块链中的所有区块并且比较hash值, 46 | // * 这个方法用来检查hash值是否是于计算出来的hash值相等, 47 | // * 同时previousHash值是否和前一个区块的hash值相等。 48 | // * 或许你会产生如下的疑问,我们就在一个主函数中创建区块链中的区块, 49 | // * 所以不存在被修改的可能性,但是你要注意的是, 50 | // * 区块链中的一个核心概念就是去中心化, 51 | // * 每一个区块可能是在网络中的某一个节点中产生的, 52 | // * 所以很有可能某个节点把自己节点中的数据修改了, 53 | // * 那么根据上述的理论数据改变会导致整个区块链的破裂, 54 | // * 也就是区块链就无效了。 55 | // * 56 | // * @return 57 | // */ 58 | // public static Boolean isChainValid() { 59 | // Block currentBlock; 60 | // Block previousBlock; 61 | // String hashTarget = new String(new char[difficulty]).replace('\0', '0'); 62 | // 63 | // // 循环区块链,检查hash,验证是否被篡改 64 | // for (int i = 1; i < blockchain.size(); i++) { 65 | // currentBlock = blockchain.get(i); 66 | // previousBlock = blockchain.get(i - 1); 67 | // //比较注册哈希和计算哈希 68 | // if (!currentBlock.hash.equals(currentBlock.calculateHash())) { 69 | // System.out.println("当前区块 hash 不相等"); 70 | // return false; 71 | // } 72 | // //比较前hash 与 注册hash 73 | // if (!previousBlock.hash.equals(currentBlock.preHash)) { 74 | // System.out.println("前区块 hash 不相等"); 75 | // return false; 76 | // } 77 | // //检查哈希是否已解决 78 | // if (!currentBlock.hash.substring(0, difficulty).equals(hashTarget)) { 79 | // System.out.println("此区块尚未挖掘"); 80 | // return false; 81 | // } 82 | // } 83 | // return true; 84 | // } 85 | // 86 | // 87 | //} 88 | --------------------------------------------------------------------------------