顾挽11.11
This commit is contained in:
parent
5c6d9475f8
commit
45d3003987
|
@ -0,0 +1 @@
|
||||||
|
EWEPEPEOGMGTELIZJUGECKIUJDBCJTCNISGPBNHLJTJUBHEWGNAKGEGAIOHJDQAJGNCFDRFZJEDMJTICAYHPJFJEJCFEBTARCUDPDEEJESDSBAEXAFJCCJCGANIQEQBUJGGEGGDNAVBQHVDCFADNAIEXAMFSDLDAAJEVCIDRDEFBDWJGBOCCHIDQBAIIICCOBMEPBHFTETGTGHHCHEDHFIDACHAVINAKGYBNDREKGCDJJJARFFDHHIEXIHCZEFJLIDEVIVAHDADHBZBBHBFCBYCGDXBPALBIEWJCGPHFESJDEGHLCFDGDXEDFEHJHNAIEYINIVGTCYGBIZGSCICDBCJIFWICDBGXISETIIETHTBNIBJNHVCXGLGFHKAVDGIWFHIRBFBVAHEZHSACJSGYHMISGJFYBQALFBDFENFVHHDJIVGJFKDGCOJDCQIVGBGBIGFFEAAEAHCJFHAMDDAQBREQCXASHAFKCOBDIGABFVGMIBHTIBHEHQCVDEDVGXEOIXJCBIERFDCIJBCZAKEACHEBELIXDVDHHMEQFEHXELCLIFJDDMJGJCALDGGMHXBWBAHUBTJPFJIVEJGCIOBMDICHGLEDCCGWBWJTAWENBUGGDNCFEHEFBUJMBOIYEFCGAOALGZFHBHGIALHEIWGNFUHKGAHXHMIMDADAJHESHYIPHOFUBKENAUINDNDXGJEIHACOAGJDAJDEGWGCBDGYGOFRARCMHCFQFRENJHFVDGDTIBELAJFCHHGZFFECFECCAGHPGUIXIWANCJESHUHNEGGUAVJGBUHWFFCOCCJFJJDAINECGRAGHMEFFHHCCBAJCSFRFUACCYIAAVILFCAXIMFZGSBKGRBHEOFKJREFITCGFGEBFGGYJAGYHWDADDCQGUJAJCHUFPIPCRFSJVJFIIBRAYISITIFDUBOABGGIQCRDRDVEDBJIMCSBKFTFKBSJVJOJGIGDGETEVELDBFVHICHECHEFVFSDYFMINIPITECJGEXACCZEWGGIYDRDMAQFUJEIEJCJAHCCJEOCEGQGSIXHBDXEIHLCTADGWDDGGIHBLHOEAIMFHHGAAFWDWGGGGDJGVFFBWCMHBHCBVCUGJIGDRDKBMBYJVHPISGZFUFREPAOBDDOJJBNEGFMIYEZEYDUAVBMDJDRBKDQJLJJBHCLEQCJILFGHAHCDHHWIUGRCQ
|
|
@ -14,18 +14,28 @@
|
||||||
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- <dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.22</version>
|
||||||
|
</dependency>-->
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.xingyuv</groupId>
|
<groupId>com.xingyuv</groupId>
|
||||||
<artifactId>spring-boot-starter-captcha-plus</artifactId>
|
<artifactId>spring-boot-starter-captcha-plus</artifactId>
|
||||||
<version>2.0.1</version>
|
<version>2.0.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.lionsoul</groupId>
|
<groupId>org.lionsoul</groupId>
|
||||||
<artifactId>ip2region</artifactId>
|
<artifactId>ip2region</artifactId>
|
||||||
|
@ -82,20 +92,72 @@
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||||
<version>1.1.10</version>
|
<version>1.2.20</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--mapstruct-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<version>1.6.0.Beta1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
<version>4.0.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 引入二维码依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.liuyueyi.media</groupId>
|
||||||
|
<artifactId>qrcode-plugin</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.12.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>${project.artifactId}</finalName>
|
<finalName>${project.artifactId}</finalName>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>1.6.0.Beta1</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.34</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
package com.guwan;
|
package com.guwan;
|
||||||
|
|
||||||
import cn.dev33.satoken.SaManager;
|
import cn.dev33.satoken.SaManager;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableFeignClients
|
||||||
public class LoginApplication {
|
public class LoginApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -13,4 +19,13 @@ public class LoginApplication {
|
||||||
System.out.println("启动成功,Sa-Token 配置如下:" + SaManager.getConfig());
|
System.out.println("启动成功,Sa-Token 配置如下:" + SaManager.getConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
//RestTemplateBuilder
|
||||||
|
private RestTemplateBuilder builder;
|
||||||
|
// 使用RestTemplateBuilder来实例化RestTemplate对象,spring默认已经注入了RestTemplateBuilder实例
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate() {
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class R extends HashMap<String, Object> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public R() {
|
public R() {
|
||||||
put("code", 0);
|
put("status", 200);
|
||||||
put("msg", "success");
|
put("msg", "success");
|
||||||
put("data", new HashMap<>());
|
put("data", new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,4 +61,10 @@ public class GlobalValue {
|
||||||
@Value("${global.file_path.static-locations}")
|
@Value("${global.file_path.static-locations}")
|
||||||
private String staticLocations;
|
private String staticLocations;
|
||||||
|
|
||||||
|
@Value("${global.faster-whisper.model}")
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
@Value("${global.faster-whisper.transitionApi}")
|
||||||
|
private String transitionApi;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.guwan.config;
|
||||||
import com.guwan.Interceptor.TokenInterceptor;
|
import com.guwan.Interceptor.TokenInterceptor;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@ -18,4 +19,13 @@ public class WebConfig implements WebMvcConfigurer {
|
||||||
.addPathPatterns("/user/**") // 拦截 /User/** 路径
|
.addPathPatterns("/user/**") // 拦截 /User/** 路径
|
||||||
.excludePathPatterns("/user/login"); // 不拦截 /User/login 路径
|
.excludePathPatterns("/user/login"); // 不拦截 /User/login 路径
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedOrigins("*") // 允许指定的源
|
||||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
|
||||||
|
.allowedHeaders("*"); // 允许的请求头
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package com.guwan.controller.login;
|
||||||
|
|
||||||
|
import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper;
|
||||||
|
import com.guwan.common.R;
|
||||||
|
import com.guwan.domain.MockScan;
|
||||||
|
import com.guwan.service.MockScanService;
|
||||||
|
import com.guwan.util.ConvertBase64Util;
|
||||||
|
import com.guwan.util.UUIDUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/easyScan")
|
||||||
|
public class EasyScanController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
MockScanService mockScanService;
|
||||||
|
|
||||||
|
@GetMapping("/11")
|
||||||
|
public R QrCode(String content) {
|
||||||
|
BufferedImage image = null;
|
||||||
|
try {
|
||||||
|
image = QrCodeGenWrapper.of(content).asBufferedImage();
|
||||||
|
Path file = new File("qrcode.png").toPath();
|
||||||
|
ImageIO.write(image, "png", file.toFile());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
mockScanService.save(new MockScan(ConvertBase64Util.imageToString(image), UUIDUtil.uuid()));
|
||||||
|
|
||||||
|
return R.ok().put("data", ConvertBase64Util.imageToString(image)).put("uuid", UUIDUtil.uuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/no")
|
||||||
|
public R QrCodeBySearch() {
|
||||||
|
BufferedImage image = null;
|
||||||
|
|
||||||
|
String content = null;
|
||||||
|
//查询封装成content
|
||||||
|
// content = ();
|
||||||
|
|
||||||
|
try {
|
||||||
|
image = QrCodeGenWrapper.of(content).asBufferedImage();
|
||||||
|
Path file = new File("qrcode.png").toPath();
|
||||||
|
ImageIO.write(image, "png", file.toFile());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
mockScanService.save(new MockScan(ConvertBase64Util.imageToString(image), UUIDUtil.uuid()));
|
||||||
|
|
||||||
|
return R.ok().put("data", ConvertBase64Util.imageToString(image)).put("uuid", UUIDUtil.uuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.guwan.controller.login;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.guwan.domain.MockScan;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 12455
|
||||||
|
* @description 针对表【mock_scan】的数据库操作Mapper
|
||||||
|
* @createDate 2024-11-11 12:32:00
|
||||||
|
* @Entity generator.domain.MockScan
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface MockScanMapper extends BaseMapper<MockScan> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.guwan.controller.login;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
|
||||||
|
import com.guwan.domain.MockScan;
|
||||||
|
import com.guwan.service.MockScanService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 12455
|
||||||
|
* @description 针对表【mock_scan】的数据库操作Service实现
|
||||||
|
* @createDate 2024-11-11 12:32:00
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MockScanServiceImpl extends ServiceImpl<MockScanMapper, MockScan>
|
||||||
|
implements MockScanService {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.guwan.controller.login;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.guwan.common.R;
|
||||||
import com.guwan.controller.login.info.UserRequest;
|
import com.guwan.controller.login.info.UserRequest;
|
||||||
import com.guwan.controller.login.info.WxMaUserInfo;
|
import com.guwan.controller.login.info.WxMaUserInfo;
|
||||||
import com.guwan.controller.login.request.ScanResult;
|
import com.guwan.controller.login.request.ScanResult;
|
||||||
|
@ -15,7 +16,7 @@ public class ScanCodeController {
|
||||||
@Operation(summary = "获取微信登录二维码信息")
|
@Operation(summary = "获取微信登录二维码信息")
|
||||||
@RequestMapping("/wxQr")
|
@RequestMapping("/wxQr")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public void wxQr(String secret) {
|
public R wxQr(String secret) {
|
||||||
// 请求易登获取二维码接口
|
// 请求易登获取二维码接口
|
||||||
String s = HttpUtil.get("https://yd.jylt.cc/api/wxLogin/tempUserId?secret=" + secret);
|
String s = HttpUtil.get("https://yd.jylt.cc/api/wxLogin/tempUserId?secret=" + secret);
|
||||||
JSONObject jsonObject = JSONUtil.parseObj(s);
|
JSONObject jsonObject = JSONUtil.parseObj(s);
|
||||||
|
@ -26,6 +27,7 @@ public class ScanCodeController {
|
||||||
System.out.println(jsonObject.getJSONObject("data").
|
System.out.println(jsonObject.getJSONObject("data").
|
||||||
getStr("qrUrl"));
|
getStr("qrUrl"));
|
||||||
}
|
}
|
||||||
|
return R.ok().put("data", jsonObject.getJSONObject("data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class UploadController {
|
||||||
}else if (extension.equals("mp4")){
|
}else if (extension.equals("mp4")){
|
||||||
catalogue = "video/";
|
catalogue = "video/";
|
||||||
}else {
|
}else {
|
||||||
return R.error().put("info", "不允许上传此类型!");
|
catalogue = "file/";
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName = catalogue + "t_" +
|
fileName = catalogue + "t_" +
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
package com.guwan.controller.login;
|
package com.guwan.controller.login;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.guwan.common.R;
|
||||||
import com.guwan.config.GlobalValue;
|
import com.guwan.config.GlobalValue;
|
||||||
|
import com.guwan.mapdemo.SimpleDestination;
|
||||||
|
import com.guwan.mapdemo.SimpleSource;
|
||||||
|
import com.guwan.mapdemo.SimpleSourceDestinationMapper;
|
||||||
|
import com.guwan.mapdemo.SimpleSourceDestinationMapperImpl;
|
||||||
import com.guwan.service.TokenService;
|
import com.guwan.service.TokenService;
|
||||||
import com.guwan.util.IPUtils;
|
import com.guwan.util.*;
|
||||||
import com.guwan.util.PathUtil;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import jakarta.annotation.security.PermitAll;
|
import jakarta.annotation.security.PermitAll;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.checkerframework.checker.units.qual.A;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
@ -17,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/user")
|
@RequestMapping("/user")
|
||||||
|
@ -27,12 +35,25 @@ public class UserController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private GlobalValue globalValue;
|
private GlobalValue globalValue;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserMapper userMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SimpleSourceDestinationMapper simpleSourceDestinationMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private VoiceServiceClient voiceServiceClient;
|
||||||
|
|
||||||
@GetMapping("/login")
|
@GetMapping("/login")
|
||||||
@PermitAll
|
@PermitAll
|
||||||
@Operation(summary = "使用账号密码登录")
|
@Operation(summary = "使用账号密码登录")
|
||||||
public String login(String userId, HttpServletRequest request) {
|
public String login(String userId, HttpServletRequest request) {
|
||||||
|
|
||||||
|
|
||||||
|
List<User> users = userMapper.selectList(new QueryWrapper<>());
|
||||||
|
System.out.println("users = " + users);
|
||||||
|
|
||||||
|
|
||||||
String test = PathUtil.path();
|
String test = PathUtil.path();
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,4 +113,31 @@ public class UserController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/test")
|
||||||
|
public void test1(){
|
||||||
|
SimpleDestination sourceName = simpleSourceDestinationMapper.sourceToDestination(new SimpleSource("sourceName", "2"));
|
||||||
|
System.out.println("sourceName = " + sourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/test123")
|
||||||
|
private R test2(String fileUrl){
|
||||||
|
System.out.println("fileUrl = " + fileUrl);
|
||||||
|
return R.ok().put("data", ToTextExample.voiceToText(fileUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/test123456")
|
||||||
|
private R test3(String fileUrl){
|
||||||
|
System.out.println("fileUrl = " + fileUrl);
|
||||||
|
return R.ok().put("data", ToTextExample2.voiceToText(fileUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/demo888")
|
||||||
|
public JSONObject convertVoiceToText(MultipartFile file, String model) {
|
||||||
|
System.out.println(voiceServiceClient.voiceToText(file, model));
|
||||||
|
return voiceServiceClient.voiceToText(file, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.guwan.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @TableName mock_scan
|
||||||
|
*/
|
||||||
|
@TableName(value ="mock_scan")
|
||||||
|
@Data
|
||||||
|
public class MockScan implements Serializable {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@TableField(value = "info")
|
||||||
|
private String info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@TableField(value = "uuid")
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public MockScan(String info, String uuid) {
|
||||||
|
this.info = info;
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object that) {
|
||||||
|
if (this == that) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (that == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != that.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MockScan other = (MockScan) that;
|
||||||
|
return (this.getInfo() == null ? other.getInfo() == null : this.getInfo().equals(other.getInfo()))
|
||||||
|
&& (this.getUuid() == null ? other.getUuid() == null : this.getUuid().equals(other.getUuid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((getInfo() == null) ? 0 : getInfo().hashCode());
|
||||||
|
result = prime * result + ((getUuid() == null) ? 0 : getUuid().hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(getClass().getSimpleName());
|
||||||
|
sb.append(" [");
|
||||||
|
sb.append("Hash = ").append(hashCode());
|
||||||
|
sb.append(", info=").append(info);
|
||||||
|
sb.append(", uuid=").append(uuid);
|
||||||
|
sb.append(", serialVersionUID=").append(serialVersionUID);
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.guwan.mapdemo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SimpleDestination {
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
// getters and setters
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.guwan.mapdemo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class SimpleSource {
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
|
||||||
|
// getters and setters
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.guwan.mapdemo;
|
||||||
|
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface SimpleSourceDestinationMapper {
|
||||||
|
SimpleDestination sourceToDestination(SimpleSource source);
|
||||||
|
SimpleSource destinationToSource(SimpleDestination destination);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.guwan.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.guwan.domain.MockScan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 12455
|
||||||
|
* @description 针对表【mock_scan】的数据库操作Service
|
||||||
|
* @createDate 2024-11-11 12:32:00
|
||||||
|
*/
|
||||||
|
public interface MockScanService extends IService<MockScan> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.guwan.test;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
|
//获取resource下文件
|
||||||
|
public class Test1 {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(ResourceUtil.getResource("banner.txt"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ConvertBase64Util {
|
||||||
|
public static String imageToString(BufferedImage image) {
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
ImageIO.write(image, "png", os);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//转base64的字符串
|
||||||
|
return Base64.encodeBase64String(os.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class EncodeUrlExample {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String url = "http://127.0.0.1:9000/yunnni/2023最新版Node.js下载安装及环境配置教程.pdf"; // 要预览文件的访问地址
|
||||||
|
try {
|
||||||
|
// 对URL进行Base64编码
|
||||||
|
String base64EncodedUrl = Base64.getEncoder().encodeToString(url.getBytes());
|
||||||
|
// 对Base64编码后的字符串进行URL编码
|
||||||
|
String encodedUrl = URLEncoder.encode(base64EncodedUrl, "UTF-8");
|
||||||
|
// 构建预览文件的URL
|
||||||
|
String previewUrl = "http://127.0.0.1:8012/onlinePreview?url=" + encodedUrl;
|
||||||
|
System.out.println("预览文件的URL: " + previewUrl);
|
||||||
|
// 这里可以打开预览文件的URL,例如使用Desktop类的browse方法
|
||||||
|
// Desktop.getDesktop().browse(new URI(previewUrl));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
public static ByteArrayResource createByteArrayResource(byte[] content, String filename) {
|
||||||
|
return new ByteArrayResource(content) {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RecognizeVo {
|
||||||
|
|
||||||
|
private ByteArrayResource fileResource;
|
||||||
|
|
||||||
|
private String model;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
文本转语音
|
||||||
|
*/
|
||||||
|
public class SimpleAudioSaver {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String urlString = "http://localhost:8534/v1/audio/speech"; // API URL
|
||||||
|
String jsonInputString = "{\"input\": \"想听个啥123\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"style\": \"\", \"rate\": 0, \"pitch\": 0}";
|
||||||
|
|
||||||
|
saveAudio(urlString, jsonInputString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveAudio(String urlString, String jsonInputString) {
|
||||||
|
try {
|
||||||
|
// 创建 URL 对象
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
// 打开连接
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
// 设置请求方式为 POST
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
|
connection.setRequestProperty("Accept", "audio/mpeg");
|
||||||
|
|
||||||
|
// 发送请求体
|
||||||
|
connection.getOutputStream().write(jsonInputString.getBytes("UTF-8"));
|
||||||
|
|
||||||
|
// 处理响应
|
||||||
|
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
// 获取输入流
|
||||||
|
InputStream inputStream = new BufferedInputStream(connection.getInputStream());
|
||||||
|
// 保存文件
|
||||||
|
try (FileOutputStream outputStream = new FileOutputStream("output.mp3")) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Audio saved as output.mp3");
|
||||||
|
} else {
|
||||||
|
System.err.println("Failed to get audio. Response code: " + connection.getResponseCode());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import com.guwan.config.GlobalValue;
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
|
||||||
|
public class ToTextExample {
|
||||||
|
private static MinioClient minioClient;
|
||||||
|
private static RestTemplate restTemplate;
|
||||||
|
private static GlobalValue globalValue;
|
||||||
|
|
||||||
|
public ToTextExample(MinioClient minioClient, RestTemplate restTemplate, GlobalValue globalValue) {
|
||||||
|
ToTextExample.minioClient = minioClient;
|
||||||
|
ToTextExample.restTemplate = restTemplate;
|
||||||
|
ToTextExample.globalValue = globalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String voiceToText(String fileUrl) {
|
||||||
|
try {
|
||||||
|
// 从 MinIO 获取文件
|
||||||
|
InputStream inputStream = minioClient.getObject(globalValue.getMinioBucketName(),
|
||||||
|
fileUrl);
|
||||||
|
ByteArrayResource fileResource = FileUtil
|
||||||
|
.createByteArrayResource(IOUtils.toByteArray(inputStream),
|
||||||
|
fileUrl);
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("file", fileResource);
|
||||||
|
body.add("model", globalValue.getModel());
|
||||||
|
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate
|
||||||
|
.postForEntity(globalValue.getTransitionApi(),
|
||||||
|
requestEntity, String.class);
|
||||||
|
|
||||||
|
JSONObject result = JSONUtil.parseObj(response.getBody());
|
||||||
|
if (result.containsKey("text")) {
|
||||||
|
String text = result.get("text").toString();
|
||||||
|
System.out.println(text);
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
System.out.println("1111");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("2222");
|
||||||
|
}
|
||||||
|
return "识别发生错误!";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.guwan.config.GlobalValue;
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ToTextExample2 {
|
||||||
|
private static MinioClient minioClient;
|
||||||
|
private static GlobalValue globalValue;
|
||||||
|
private static WebClient webClient;
|
||||||
|
|
||||||
|
public ToTextExample2(MinioClient minioClient, GlobalValue globalValue) {
|
||||||
|
ToTextExample2.minioClient = minioClient;
|
||||||
|
ToTextExample2.globalValue = globalValue;
|
||||||
|
|
||||||
|
// 初始化 WebClient
|
||||||
|
ToTextExample2.webClient = WebClient.builder()
|
||||||
|
.baseUrl(globalValue.getTransitionApi())
|
||||||
|
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String voiceToText(String fileUrl) {
|
||||||
|
try {
|
||||||
|
// 从 MinIO 获取文件
|
||||||
|
InputStream inputStream = minioClient.getObject(globalValue.getMinioBucketName(), fileUrl);
|
||||||
|
ByteArrayResource fileResource = FileUtil.createByteArrayResource(IOUtils.toByteArray(inputStream), fileUrl);
|
||||||
|
|
||||||
|
// 设置请求体
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("file", fileResource);
|
||||||
|
body.add("model", globalValue.getModel());
|
||||||
|
|
||||||
|
// 发送请求并处理响应
|
||||||
|
String response = webClient.post()
|
||||||
|
.uri("") // 这里假设是 POST 请求到基础 URL
|
||||||
|
.body(BodyInserters.fromMultipartData(body))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class)
|
||||||
|
.block(); // 同步调用,若需要异步处理,可以去掉 block()
|
||||||
|
|
||||||
|
// 解析响应 JSON
|
||||||
|
JSONObject result = JSONUtil.parseObj(response);
|
||||||
|
if (result.containsKey("text")) {
|
||||||
|
String text = result.get("text").toString();
|
||||||
|
System.out.println(text);
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
System.out.println("1111");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(); // 输出异常信息
|
||||||
|
System.out.println("2222");
|
||||||
|
}
|
||||||
|
return "识别发生错误!";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import com.guwan.common.R;
|
||||||
|
import com.guwan.config.GlobalValue;
|
||||||
|
import com.guwan.config.MinioConfig;
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import io.minio.PutObjectOptions;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UploadUtil {
|
||||||
|
private static MinioClient minioClient;
|
||||||
|
|
||||||
|
private static MinioConfig minioConfig;
|
||||||
|
|
||||||
|
public UploadUtil(MinioClient minioClient,
|
||||||
|
MinioConfig minioConfig) {
|
||||||
|
UploadUtil.minioClient = minioClient;
|
||||||
|
UploadUtil.minioConfig = minioConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String gbUpload(MultipartFile file) {
|
||||||
|
if (file.isEmpty() || file.getSize() == 0) {
|
||||||
|
System.out.println("文件不能为空");
|
||||||
|
}
|
||||||
|
String fileName = null;
|
||||||
|
|
||||||
|
String catalogue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); //后缀名
|
||||||
|
if (extension.equals("png") || extension.equals("jpg")){
|
||||||
|
catalogue = "photo/";
|
||||||
|
}else if (extension.equals("mp4")){
|
||||||
|
catalogue = "video/";
|
||||||
|
}else {
|
||||||
|
catalogue = "files/";
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName = catalogue + "t_" +
|
||||||
|
UUID.randomUUID().toString().replace("-","") +
|
||||||
|
"." + extension;
|
||||||
|
InputStream inputStream = file.getInputStream();
|
||||||
|
PutObjectOptions putObjectOptions = new PutObjectOptions(inputStream.available(), -1);
|
||||||
|
putObjectOptions.setContentType(file.getContentType());
|
||||||
|
minioClient.putObject(
|
||||||
|
minioConfig.getBucketName(), fileName, inputStream, putObjectOptions);
|
||||||
|
inputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
System.out.println("方法结束");
|
||||||
|
|
||||||
|
return minioConfig.getMinioEndpoint() + "/" +
|
||||||
|
minioConfig.getBucketName() + "/" + fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.guwan.util;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@FeignClient(name = "voiceService", url = "http://127.0.0.1:8532")
|
||||||
|
public interface VoiceServiceClient {
|
||||||
|
|
||||||
|
@PostMapping(value = "/v1/audio/transcriptions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
JSONObject voiceToText(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestPart("model") String model);
|
||||||
|
}
|
|
@ -9,12 +9,22 @@ spring:
|
||||||
password: aliredis666
|
password: aliredis666
|
||||||
database: 1
|
database: 1
|
||||||
datasource:
|
datasource:
|
||||||
druid:
|
url: jdbc:mysql://127.0.0.1:3306/studb?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://127.0.0.1:3306/studb
|
|
||||||
username: root
|
username: root
|
||||||
password: X1p6x5irECRCLpqsOAIjh1w4VBPK0x3AP1WNNz8xVmhGx98BANEsw2KQKmBIagzCVo6aBrveoHwWa6FA9gXcwQ==
|
password: oB54oq8cIH2SyRTFWDPc2U4g70P2Jit/E1CxoShgWBSJGqQt6vCcz0mjEO6+oPHEwQ7XH2vkMApmrHOgMv07LA== # 修改为控制台输出的password
|
||||||
connection-properties: config.decrypt=true;config.decrypt.key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIQ/kwu9OapBDTOTUzM7CGWbbo2+qfCybUDctQcKeGptz8nhQYAzsU9JyfaDQE9RhFj7pwwD8JgB4qJWycicdXcCAwEAAQ==
|
#druid数据源配置
|
||||||
|
druid:
|
||||||
|
filter:
|
||||||
|
# 启用Druid的过滤器配置
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
connect-properties:
|
||||||
|
# 启用Druid的连接属性解密功能
|
||||||
|
config.decrypt: true
|
||||||
|
config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKEHrmL+L+Q8yRUA8BKnZVsxXHnVw2b/Y80f0U4r4P9YkQs+gJjtP0AjMpXpW9muJq+mxzwKHqRUJeO0JKfpF/ECAwEAAQ== # 控制台输出的publicKey
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
|
@ -53,6 +63,9 @@ global:
|
||||||
accessKey: admin
|
accessKey: admin
|
||||||
secretKey: admin123456
|
secretKey: admin123456
|
||||||
bucketName: cuwan
|
bucketName: cuwan
|
||||||
|
faster-whisper:
|
||||||
|
model: "/model/faster-whisper-small/"
|
||||||
|
transitionApi: "http://127.0.0.1:8532/v1/audio/transcriptions"
|
||||||
|
|
||||||
file_path:
|
file_path:
|
||||||
static-locations: \Guwan\
|
static-locations: \Guwan\
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
<artifactId>old-face</artifactId>
|
<artifactId>old-face</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
<artifactId>old-nacos</artifactId>
|
<artifactId>old-nacos</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
Binary file not shown.
60
pom.xml
60
pom.xml
|
@ -18,8 +18,8 @@
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Lombok组件 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
@ -48,11 +49,22 @@
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Boot Starter Test (可选) -->
|
<!-- 单元测试组件 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<version>3.1.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -62,41 +74,52 @@
|
||||||
<version>2.5.0</version>
|
<version>2.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-all</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>5.8.32</version>
|
<version>5.8.32</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--mysql-db-->
|
<!-- MySql数据库-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>8.0.33</version>
|
<version>8.0.33</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--mp-->
|
<!-- Mybatis和分页组件 -->
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
|
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.pagehelper</groupId>
|
||||||
|
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||||
|
<version>1.4.7</version>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--mp和分页插件-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
<version>3.5.7</version>
|
<version>3.5.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.shardingsphere</groupId>
|
<groupId>com.github.pagehelper</groupId>
|
||||||
<artifactId>shardingsphere-jdbc-core</artifactId>
|
<artifactId>pagehelper</artifactId>
|
||||||
<version>5.4.1</version>
|
<version>6.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- HikariCP -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.zaxxer</groupId>
|
|
||||||
<artifactId>HikariCP</artifactId>
|
|
||||||
<version>5.0.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -105,4 +128,5 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</project>
|
</project>
|
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
|
@ -11,9 +11,26 @@
|
||||||
|
|
||||||
<artifactId>ss-Demo</artifactId>
|
<artifactId>ss-Demo</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- ShardingSphere分库分表 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.shardingsphere</groupId>
|
||||||
|
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
|
||||||
|
<version>5.2.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
|
|
||||||
public class SsDemoApplication {
|
public class SsDemoApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
@ -2,25 +2,31 @@ package com.guwan.controller;
|
||||||
|
|
||||||
|
|
||||||
import com.guwan.dal.dataobject.Order;
|
import com.guwan.dal.dataobject.Order;
|
||||||
import com.guwan.service.OrderService;
|
import com.guwan.dal.mysql.OrderMapper;
|
||||||
|
import com.guwan.service.IOrderService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import java.util.List;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/orders")
|
@RequestMapping("/orders")
|
||||||
public class OrderController {
|
public class OrderController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private OrderService orderService;
|
private IOrderService orderService;
|
||||||
|
|
||||||
@PostMapping
|
@Autowired
|
||||||
public void createOrder(@RequestBody Order order) {
|
private OrderMapper orderMapper;
|
||||||
orderService.createOrder(order);
|
|
||||||
|
@GetMapping
|
||||||
|
public void createOrder() {
|
||||||
|
System.out.println("orderService = ");
|
||||||
|
|
||||||
|
for (int i = 1; i < 100; i++) {
|
||||||
|
Order order = new Order(i, i, i);
|
||||||
|
orderMapper.insert(order);
|
||||||
|
//orderService.save(order);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{userId}")
|
|
||||||
public List<Order> getOrders(@PathVariable Long userId) {
|
|
||||||
return orderService.getOrdersByUserId(userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,25 @@
|
||||||
package com.guwan.dal.dataobject;
|
package com.guwan.dal.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
|
|
||||||
|
@TableName("tb_order")
|
||||||
public class Order {
|
public class Order {
|
||||||
private Long orderId;
|
|
||||||
private Long userId;
|
|
||||||
private String orderContent;
|
private Integer orderId;
|
||||||
|
|
||||||
|
private Integer sellerId;
|
||||||
|
|
||||||
|
private Integer buyerId;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,15 +1,14 @@
|
||||||
package com.guwan.dal.mysql;
|
package com.guwan.dal.mysql;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.guwan.dal.dataobject.Order;
|
import com.guwan.dal.dataobject.Order;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface OrderMapper {
|
public interface OrderMapper extends BaseMapper<Order> {
|
||||||
void insertOrder(Order order);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Order> selectOrdersByUserId(@Param("userId") Long userId);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.guwan.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.guwan.dal.dataobject.Order;
|
||||||
|
|
||||||
|
public interface IOrderService extends IService<Order> {
|
||||||
|
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
package com.guwan.service;
|
|
||||||
|
|
||||||
|
|
||||||
import com.guwan.dal.dataobject.Order;
|
|
||||||
import com.guwan.dal.mysql.OrderMapper;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class OrderService {
|
|
||||||
@Autowired
|
|
||||||
private OrderMapper orderMapper;
|
|
||||||
|
|
||||||
public void createOrder(Order order) {
|
|
||||||
orderMapper.insertOrder(order);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Order> getOrdersByUserId(Long userId) {
|
|
||||||
return orderMapper.selectOrdersByUserId(userId);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.guwan.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.guwan.dal.dataobject.Order;
|
||||||
|
import com.guwan.dal.mysql.OrderMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,36 +1,68 @@
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
tomcat:
|
||||||
|
uri-encoding: UTF-8
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
profiles:
|
|
||||||
active: dev
|
|
||||||
application:
|
application:
|
||||||
name: sharging-jdbc-demo
|
name: boot-shard
|
||||||
|
# 分库分表配置
|
||||||
shardingsphere:
|
shardingsphere:
|
||||||
datasource:
|
datasource:
|
||||||
names: master,slave1
|
# 默认数据源
|
||||||
master:
|
sharding:
|
||||||
type: com.zaxxer.hikari.HikariDataSource # 数据源类型
|
default-data-source-name: db_master
|
||||||
url: jdbc:mysql://localhost:3306/course_master_db # 数据库连接地址
|
names: db_master,db_0,db_1
|
||||||
username: root # 用户名
|
db_master:
|
||||||
password: 123456 # 密码
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
driver-class-name: com.mysql.jdbc.Driver # 数据库驱动
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
slave1:
|
jdbc-url: jdbc:mysql://localhost:3306/shard_db?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=true
|
||||||
type: com.zaxxer.hikari.HikariDataSource # 数据源类型
|
username: root
|
||||||
url: jdbc:mysql://localhost:3306/course_db # 数据库连接地址
|
password: 123456
|
||||||
username: root # 用户名
|
db_0:
|
||||||
password: 123456 # 密码
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
driver-class-name: com.mysql.jdbc.Driver # 数据库驱动
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
jdbc-url: jdbc:mysql://localhost:3306/shard_db_0?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=true
|
||||||
|
username: root
|
||||||
|
password: 123456
|
||||||
|
db_1:
|
||||||
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
jdbc-url: jdbc:mysql://localhost:3306/shard_db_1?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=true
|
||||||
|
username: root
|
||||||
|
password: 123456
|
||||||
rules:
|
rules:
|
||||||
readwrite-splitting:
|
sharding:
|
||||||
data-sources:
|
tables:
|
||||||
mds: #名字自定义
|
# tb_order逻辑
|
||||||
type: static #类型 静态获取
|
tb_order:
|
||||||
|
actual-data-nodes: db_${0..1}.tb_order_${0..2}
|
||||||
|
# tb_order库路由
|
||||||
|
database-strategy:
|
||||||
|
standard:
|
||||||
|
sharding-column: order_id
|
||||||
|
sharding-algorithm-name: database_inline
|
||||||
|
# tb_order表路由
|
||||||
|
table-strategy:
|
||||||
|
standard:
|
||||||
|
sharding-column: order_id
|
||||||
|
sharding-algorithm-name: table_inline
|
||||||
|
sharding-algorithms:
|
||||||
|
# tb_order库路由算法
|
||||||
|
database_inline:
|
||||||
|
type: INLINE
|
||||||
props:
|
props:
|
||||||
auto-aware-data-source-name: master
|
algorithm-expression: db_${order_id % 2}
|
||||||
write-data-source-name: master
|
# tb_order表路由算法
|
||||||
read-data-source-names: slave1
|
table_inline:
|
||||||
load-balancer-name: read-random #读写分离规则自定义命名
|
type: INLINE
|
||||||
load-balancers:
|
|
||||||
read-random:
|
|
||||||
type: ROUND_ROBIN # 轮询负载均衡
|
|
||||||
props:
|
props:
|
||||||
sql-show: true # 是否打印sql
|
algorithm-expression: tb_order_${order_id % 3}
|
||||||
sql-simple: true # 打印简单的sql
|
props:
|
||||||
|
sql-show: true
|
||||||
|
sql-comment-parse-enabled: true
|
||||||
|
|
||||||
|
# mybatis 配置
|
||||||
|
mybatis-plus:
|
||||||
|
configuration:
|
||||||
|
map-underscore-to-camel-case: true
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<mapper namespace="com.guwan.dal.mysql.OrderMapper" >
|
||||||
<mapper namespace="com.guwan.dal.mysql.OrderMapper">
|
|
||||||
<insert id="insertOrder" parameterType="com.guwan.dal.dataobject.Order">
|
|
||||||
INSERT INTO t_order (order_id, user_id, order_content) VALUES (#{orderId}, #{userId}, #{orderContent})
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<select id="selectOrdersByUserId" parameterType="Long" resultType="com.guwan.dal.dataobject.Order">
|
|
||||||
SELECT * FROM t_order WHERE user_id = #{userId}
|
|
||||||
</select>
|
|
||||||
</mapper>
|
</mapper>
|
Loading…
Reference in New Issue