Prechádzať zdrojové kódy

文件上传-本地
新增加密工具类

hjp 2 týždňov pred
rodič
commit
fae6d8fee5

+ 3 - 0
src/main/java/com/sqx/config/ShiroConfig.java

@@ -41,6 +41,9 @@ public class ShiroConfig {
         shiroFilter.setFilters(filters);
 
         Map<String, String> filterMap = new LinkedHashMap<>();
+        filterMap.put("/file/**", "anon"); // 这里放行你自定义的静态资源目录
+        filterMap.put("/static/**", "anon"); // 其他静态资源(如css, js等)
+
         filterMap.put("/webjars/**", "anon");
         filterMap.put("/druid/**", "anon");
         filterMap.put("/app/wxPay/notifyJsApi", "anon");

+ 6 - 0
src/main/java/com/sqx/modules/app/config/WebMvcConfig.java

@@ -7,6 +7,7 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import java.util.List;
@@ -31,6 +32,11 @@ public class WebMvcConfig implements WebMvcConfigurer {
     public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
         argumentResolvers.add(loginUserHandlerMethodArgumentResolver);
     }
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        registry.addResourceHandler("/file/**")
+                .addResourceLocations("file:/D:/JG/file/");
+    }
 
 
 

+ 1 - 1
src/main/java/com/sqx/modules/car/controller/app/AppCarController.java

@@ -73,7 +73,7 @@ public class AppCarController {
         driver.setDriverColor(car.getCarColor());
         driver.setDriverPlate(car.getCarPlate());
         driver.setDriverBrand(car.getCarBrand());
-        driver.setStatus(car.getStatus());
+//        driver.setStatus(car.getStatus());
         driverService.updateDriver(driver);
         List<Car> carList = carService.list(new QueryWrapper<Car>().eq("user_id", userId));
         if (carList.size() == 1){

+ 31 - 1
src/main/java/com/sqx/modules/file/AliFileUploadController.java

@@ -12,6 +12,11 @@ import org.jaudiotagger.audio.AudioFileIO;
 import org.jaudiotagger.audio.mp3.MP3AudioHeader;
 import org.jaudiotagger.audio.mp3.MP3File;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StreamUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -67,7 +72,10 @@ public class AliFileUploadController {
                 String http = commonRepository.findOne(19).getValue();
                 String[] split = http.split("://");
                 // 上传文件路径
-                String filePath ="/www/wwwroot/"+split[1]+"/file/uploadPath";
+                // FIXME: 2025/5/23 0023 linux路径 临时换windows路径
+//                String filePath ="/www/wwwroot/"+split[1]+"/file/uploadPath";
+                String filePath = "D:/JG/file/uploadPath";
+                // FIXME: 2025/5/23 0023 END
                 // 上传并返回新文件名称
                 String fileName = FileUploadUtils.upload(filePath, file);
                 String url = http +fileName;
@@ -82,6 +90,28 @@ public class AliFileUploadController {
 
     }
 
+    @GetMapping("/image")
+    public ResponseEntity<byte[]> getRemoteImage(@RequestParam String imageUrl) {
+        File file = new File(imageUrl);
+        if (!file.exists() || !file.isFile()) {
+            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
+        }
+
+        try (FileInputStream fis = new FileInputStream(file)) {
+            byte[] bytes = StreamUtils.copyToByteArray(fis);
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.IMAGE_JPEG); // 根据实际图片类型设置
+            headers.setContentLength(bytes.length);
+
+            return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+        }
+    }
+
+
     @RequestMapping(value = "/uploadUniApp", method = RequestMethod.POST)
     @ApiOperation("文件上传")
     @ResponseBody

+ 95 - 0
src/main/java/com/sqx/modules/utils/AESCBCWithRandomIV.java

@@ -0,0 +1,95 @@
+package com.sqx.modules.utils;
+
+import lombok.val;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+public class AESCBCWithRandomIV {
+
+    private static final String AES = "AES";
+    private static final String AES_CBC_PADDING = "AES/CBC/PKCS5Padding";
+    private static final int IV_SIZE = 16; // 16 bytes for AES block size
+    private static final int KEY_SIZE = 128;
+
+    // ⚠️ 真实项目中,请从安全的配置中读取密钥,避免硬编码!
+    private static final String SECRET_KEY = "nihyMG%DJ0I0nhlA"; // 16 bytes = 128 bits
+
+    /**
+     * AES CBC 加密,随机生成 IV 并一起编码返回(IV + CipherText)
+     */
+    public static String encrypt(String plainText,String secretKey) throws Exception {
+        byte[] keyBytes = secretKey.getBytes("UTF-8");
+        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES);
+
+        // 随机 IV
+        byte[] ivBytes = new byte[IV_SIZE];
+        new SecureRandom().nextBytes(ivBytes);
+        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+
+        Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
+        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
+
+        // 拼接 IV + 加密内容
+        byte[] combined = new byte[IV_SIZE + encryptedBytes.length];
+        System.arraycopy(ivBytes, 0, combined, 0, IV_SIZE);
+        System.arraycopy(encryptedBytes, 0, combined, IV_SIZE, encryptedBytes.length);
+
+        return Base64.getEncoder().encodeToString(combined);
+    }
+
+    /**
+     * AES CBC 解密,从密文中提取 IV 解密
+     */
+    public static String decrypt(String base64CipherText,String secretKey) throws Exception {
+        byte[] combined = Base64.getDecoder().decode(base64CipherText);
+
+        byte[] ivBytes = new byte[IV_SIZE];
+        byte[] encryptedBytes = new byte[combined.length - IV_SIZE];
+
+        System.arraycopy(combined, 0, ivBytes, 0, IV_SIZE);
+        System.arraycopy(combined, IV_SIZE, encryptedBytes, 0, encryptedBytes.length);
+
+        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), AES);
+
+        Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
+        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+        byte[] decrypted = cipher.doFinal(encryptedBytes);
+
+        return new String(decrypted, "UTF-8");
+    }
+
+    public static String getSecretKey(){
+        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-=.$%^&*#";
+        SecureRandom random = new SecureRandom();
+        StringBuilder key = new StringBuilder(16);
+
+        for (int i = 0; i < 16; i++) {
+            key.append(chars.charAt(random.nextInt(chars.length())));
+        }
+        System.out.println("随机生成的密钥: " + key.toString());
+        return key.toString();
+    }
+
+    // 🔍 示例测试
+    public static void main(String[] args) throws Exception {
+        String text = "210421200001084233";
+        val key = getSecretKey();
+        String encrypted = encrypt(text,key);
+        String decrypted = decrypt(encrypted,key);
+
+
+        System.out.println("原文: " + text);
+        System.out.println("加密: " + encrypted);
+        System.out.println("解密: " + decrypted);
+    }
+}
+
+

+ 51 - 0
src/main/java/com/sqx/modules/utils/AESUtil.java

@@ -0,0 +1,51 @@
+package com.sqx.modules.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+
+public class AESUtil {
+
+    // 密钥(必须是16/24/32字节的长度)
+    private static final String KEY = "1234567890abcdef"; // 16字节 = 128位
+
+    // 算法/模式/填充
+    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String data) throws Exception {
+        Cipher cipher = Cipher.getInstance(ALGORITHM);
+        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
+        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
+        byte[] encrypted = cipher.doFinal(data.getBytes("UTF-8"));
+        return Base64.getEncoder().encodeToString(encrypted);
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String base64Encrypted) throws Exception {
+        Cipher cipher = Cipher.getInstance(ALGORITHM);
+        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
+        cipher.init(Cipher.DECRYPT_MODE, keySpec);
+        byte[] decodedBytes = Base64.getDecoder().decode(base64Encrypted);
+        byte[] decrypted = cipher.doFinal(decodedBytes);
+        return new String(decrypted, "UTF-8");
+    }
+
+    // 测试
+    public static void main(String[] args) throws Exception {
+        String plainText = "210421200001084233";
+        String encrypted = encrypt(plainText);
+        String decrypted = decrypt(encrypted);
+
+        System.out.println("原文: " + plainText);
+        System.out.println("加密后: " + encrypted);
+        System.out.println("解密后: " + decrypted);
+    }
+}
+

+ 4 - 0
src/main/resources/application.yml

@@ -47,6 +47,10 @@ spring:
     throw-exception-if-no-handler-found: true
     pathmatch:
       matching-strategy: ant_path_matcher
+  web:
+    resources:
+      # 本地文件路径
+      static-locations: file:D:/JG/file/
 #  resources:
 #    add-mappings: false