日期:7月20日
所学出处:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)
//解决办法: 采用MD5加密方式加密(SpringBoot自带)
DigestUtils.md5DigestAsHex(password.getBytes()) //.getBytes()转换为二进制
//解决方法: 采用属性拷贝的方式(SpringBoot自带)
BeanUtils.copyProperties(employeeDTO,employee); //将前者数据拷贝给后者
注意:拷贝的条件是后者需要拥有前者的所有属性;
//解决方法: 通过ThreadLocal的线程方式存储id数据
ThreadLocal<Long> threadLocal = new ThreadLocal<>();
注意:只用在同一线程下才能存储获取到参数,使用前需要测试是否处于同一线程中:Thread.currentThread().getId()
地址:https://blog.csdn.net/LitongZero/article/details/120543138
//解决办法: 扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//创建一个消息转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到Mvc框架的转换器集合中(将我们所设定的转换器设置为第一个使用)
converters.add(0,converter);
}
地址:https://www.cnblogs.com/zxy1221/p/16691950.html
//解决方法: 使用MP的公共字段填充 或 自己定义一个公共字段填充
//自定义公共字段填充
1.自定义一个注解AutoFill,标识需要进行公共字段自动填充的方法,内部需定义操作类型
2.自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
3.在Mapper的方法上加入AutoFill注解
地址:https://blog.csdn.net/remsqks/article/details/131580218
//1.注册小程序 https://mp.weixin.qq.com/wxopen/waregister?action=step1
//2.完善小程序信息
//3.下载开发者工具 https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html
地址:https://www.bilibili.com/video/BV1TP411v7v6?p=71&vd_source=feade4dbeca9dfe8bb4afc70a47410bd
//解决方法 使用com.alibaba.fastjson依赖中的JSONObject方法
JSONObject jsonObject = JSON.parseObject(json);
String openid = jsonObject.getString("openid");
地址:https://blog.csdn.net/qq_42981242/article/details/109779075
//业务功能:
1.查询地址列表
2.新增或删除、修改地址
3.设置或查询默认地址
//解决方法 获取微信支付平台证书、商务私钥文件
//解决方法 获取临时域名(通过Cpolar获取)
地址:https://dashboard.cpolar.com/login
//解决方法 使用Spring Task定时任务框架
@Scheduled(cron = "0 * * * * ? *") //每分钟执行一次
//解决方法 使用WebSocket通信协议
地址:https://blog.csdn.net/m0_64466983/article/details/126071939
//解决方法 Stream流的使用
List<String> names = nameList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
//解决方法 org.apache.commons.lang3依赖中的工具类
(StringUtils.join(names,",") //取出集合中参数以逗号拼接 "1","2","3"
//解决方法 InputStream in = this.getClass().getClassLoader().getResourceAsStream()
//当前端传输的数据结构与后端实体类相差过大时,会创建DTO去接收前端参数,后续将DTO接收参数拷贝给实体类
//当前项目中通过DTO来对接前端传递的参数
//这一项目中并未使用MyBatisPlus完成分页查询,但是MP的使用更加便捷,可以快速得到Page对象
//当使用MybatisPlus完成分页查询时需要 配置MP的分页插件
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
//ThreadLocal的应用场景暂时只了解到了线程的数据暂存储以及传递获取
//使用这一部分内容需要一个对象转换器,对于对象转换器的内容比较固定,需要时可以网上复制
//当前项目使用Redis实现店铺状态的存储与修改,用到了opsForValue数据类型
//这个项目告诉了我单纯的Redis缓存注解只是针对于部分内容的,对于对象的存储之类的操作还是需要用到常用命令
//缓存注解的使用@Cacheable(cacheNames = "usercache" , key = "#categoryId) key的生成:userchche::10
//cacheNames的功能似乎和value的功能是一样的,因此书写时写一个就够了
//默认情况下Date可以识别yyyy/MM/dd格式;当使用@DateTimeFormat标志日期型参数后,必须要写对应格式
public String save4(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){}
Parameter ‘status’ not found. Available parameters are [orderTime, stauts, param1, param2]
原因:OrderMapper中SQL的参数输入错误,于SQL语句中传参不一致
//基于spring-core工具加密
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.7.RELEASE</version>
案例:
public class MD5Util {
public static String getMd5Plus(String pwd){
//先进行第一层加密
String md1 = DigestUtils.md5DigestAsHex(pwd.getBytes());
//截取第一层加密后的密文的前6位
String substring6 = md1.substring(0, 6);//前包含后不包含
//再对密文+前6位再加密
String md5plus = DigestUtils.md5DigestAsHex((md1+substring6).getBytes());
return md5plus;
}
}
//代替文件上传与下载的本地存储方式,采用云存储的方式存储数据
操作流程:
1.创建bucket (创建时权限控制中的读写权限需要选择公共读)
2.获取AccessKey(密钥)
3.添加依赖
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
4.根据帮助文档实现内容
地址:https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.32007.0.0.382624cbCKVhyM
核心API:HttpClient、HttpClients、CloseableHttpClient、HttpGet、HttpPost
//依赖
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
//发送请求步骤
1.创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
2.创建Http请求对象
//GET
HttpGet httpGet = new HttpGet("http://httpbin.org/get");
//Post
HttpPost httpPost = new HttpPost("http://httpbin.org/post");
JSONObject js = new JSONObject();
js.put("username","admin");
StringEntity entity = new StringEntity(js.toString) ;
//指定请求编码方式
entity.setContentEncoding("utf-8");
//数据格式
entity.setContentType("application/json");
httpPost.setEntity(entity);
3.调用HttpClient的execute方法发送请求
CloseableHttpResponse response = httpClient.execute(httpGet);
4.解析response,返回结果
// 获取状态码
int status = response.getStatusLine().getStatusCode();
// 获取对象
HttpEntity entity = response.getEntity();
// 解析对象返回结果
String html = EntityUtils.toString(entity);
5.释放连接
response.close();
httpClient.close();
注意:
地址:https://blog.csdn.net/yangsf_/article/details/124527687
public User wxLogin(UserLoginDTO userLoginDTO){
//调用微信接口服务,获得当前微信用户的openid
Map<String, String> map = new HashMap<>();
map.put("appid",weChatProperties.getAppid());
map.put("secret",weChatProperties.getSecret());
map.put("js_code",userLoginDTO.getCode());
//发送请求
String json = HttpClientUtil.doGet(WX_LOGIN, map);
//解析JSON
JSONObject jsonObject = JSON.parseObject(json);
String openid = jsonObject.getString("openid");
//判断openid是否为空,如果为空表示登录失败,抛出业务异常
if (openid == null){
throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
}
//判断是否为新用户
User user = userMapper.getByOpenid(openid);
if (user == null){
user = User.builder()
.openid(openid)
.createTime(LocalDateTime.now())
.build();
userMapper.insert(user);
}
return user;
}
关联:发送请求的工具类 F:\Sky Delivery\sky-take-out\sky-common\src\main\java\com\sky\utils\HttpClientUtil.java
注意:微信支付的格式相对于比较固定,且想要使用需要条件,因此暂不深入了解
微信支付学习地址:https://pay.weixin.qq.com/static/product/product_indexshtml
//简介: Spring框架提供的任务调度工具,可以按照约定时间自动执行某个代码逻辑
//定位: 定时任务框架
//cron表达式 定义任务触发的时间
//规则: 分为6或7个域,由空格分隔开;每个域分别表示 秒、分、时、日、月、周、年(可选)
//步骤:
1.导入依赖spring-context Spring Task是一个小框架包含在spring-context中
2.启动类添加注解@EnableScheduling 开启任务调度
3.自定义定时任务类
//举例
@Component
@Slf4j
@Api(tags = "定时任务类处理订单状态")
public class OrderTask {
@Scheduled(cron = "0 * * * * ? *") //每分钟执行一次
public void processTimeoutOrder(){
log.info("定时处理超时订单:{}", LocalDateTime.now());
}
}
cron表达式地址:http://cron.qqe2.com
简介:WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信一浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
1.导入WebSocket的maven坐标
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
2.WebSocket服务端组件WebSocketServer,用于和客户端通信(基本固定格式)
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
//存放会话对象
private static Map<String, Session> sessionMap = new HashMap();
//连接建立成功调用的方法
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
System.out.println("客户端:" + sid + "建立连接");
sessionMap.put(sid, session);
}
//收到客户端消息后调用的方法
@OnMessage
public void onMessage(String message, @PathParam("sid") String sid) {
System.out.println("收到来自客户端:" + sid + "的信息:" + message);
}
//连接关闭调用的方法
@OnClose
public void onClose(@PathParam("sid") String sid) {
System.out.println("连接断开:" + sid);
sessionMap.remove(sid);
}
//群发
public void sendToAllClient(String message) {
Collection<Session> sessions = sessionMap.values();
for (Session session : sessions) {
try {
//服务器向客户端发送消息
session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3.导入配置类WebSocketConfiguration,注册Websocket的服务端组件(基本固定格式)
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
4.使用
//通过websocket向客户端浏览器推送消息 type orderId content
Map map = new HashMap();
map.put("type",1);// ,2表示用户催单
map.put("orderId",orders.getId());
map.put("content","订单号:" + orders.getNumber());
String json = JSON.toJSONString(map);
webSocketServer.sendToAllClient(json);
地址:https://blog.csdn.net/m0_64466983/article/details/126071939
注册账号:https://passport.baidu.com/v2/?reg&tt=1671699340600&overseas=&gid=CF954C2-A3D2-417F-9FE6-B0F249ED7E33&tpl=pp&u=https%3A%2F%2Flbsyun.baidu.com%2Findex.php%3Ftitle%3D%E9%A6%96%E9%A1%B5
登录百度地图开放平台:https://lbsyun.baidu.com/
进入控制台,创建应用,获取AK:
相关接口:
https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding
https://lbsyun.baidu.com/index.php?title=webapi/directionlite-v1
配置外卖商家店铺地址和百度地图的AK:
改造OrderServiceImpl,注入上面的配置项:
@Value("${sky.shop.address}")
private String shopAddress;
@Value("${sky.baidu.ak}")
private String ak;
在OrderServiceImpl中提供校验方法:
/**
* 检查客户的收货地址是否超出配送范围
*/
private void checkOutOfRange(String address) {
Map map = new HashMap();
map.put("address",shopAddress);
map.put("output","json");
map.put("ak",ak);
//获取店铺的经纬度坐标
String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);
JSONObject jsonObject = JSON.parseObject(shopCoordinate);
if(!jsonObject.getString("status").equals("0")){
throw new OrderBusinessException("店铺地址解析失败");
}
//数据解析
JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
String lat = location.getString("lat");
String lng = location.getString("lng");
//店铺经纬度坐标
String shopLngLat = lat + "," + lng;
map.put("address",address);
//获取用户收货地址的经纬度坐标
String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);
jsonObject = JSON.parseObject(userCoordinate);
if(!jsonObject.getString("status").equals("0")){
throw new OrderBusinessException("收货地址解析失败");
}
//数据解析
location = jsonObject.getJSONObject("result").getJSONObject("location");
lat = location.getString("lat");
lng = location.getString("lng");
//用户收货地址经纬度坐标
String userLngLat = lat + "," + lng;
map.put("origin",shopLngLat);
map.put("destination",userLngLat);
map.put("steps_info","0");
//路线规划
String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map);
jsonObject = JSON.parseObject(json);
if(!jsonObject.getString("status").equals("0")){
throw new OrderBusinessException("配送路线规划失败");
}
//数据解析
JSONObject result = jsonObject.getJSONObject("result");
JSONArray jsonArray = (JSONArray) result.get("routes");
Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance");
if(distance > 5000){
//配送距离超过5000米
throw new OrderBusinessException("超出配送范围");
}
}
在OrderServiceImpl的submitOrder方法中调用上面的校验方法:
ApacheECharts 是一款基于Javascript 的数据可视化图表库,提供直观,生动,可交与,可个性化定制的数据可视化图表
//这是对于前端框架的内容
//对于后端而言只需要提供规范的数据格式即可
地址:https://echarts.apache.org
Apache POl 是一个处理Miscrsoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI在Java 程
序中对Miscrosoft Office各种文件进行读写操作。
一般情况下,POI都是用于操作 Excel文件
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
public class POITest {
public static void write() throws Exception{
//在内存中创建一个Excel文件对象
XSSFWorkbook excel = new XSSFWorkbook();
//创建Sheet页
XSSFSheet sheet = excel.createSheet("itcast");
//在Sheet页中创建行,0表示第1行
XSSFRow row1 = sheet.createRow(0);
//创建单元格并在单元格中设置值,单元格编号也是从0开始,1表示第2个单元格
row1.createCell(1).setCellValue("姓名");
row1.createCell(2).setCellValue("城市");
XSSFRow row2 = sheet.createRow(1);
row2.createCell(1).setCellValue("张三");
row2.createCell(2).setCellValue("北京");
FileOutputStream out = new FileOutputStream(new File("D:\\itcast.xlsx"));
//通过输出流将内存中的Excel文件写入到磁盘上
excel.write(out);
//关闭资源
out.flush();
out.close();
excel.close();
}
}
public class POITest {
public static void read() throws Exception{
FileInputStream in = new FileInputStream(new File("D:\\itcast.xlsx"));
//通过输入流读取指定的Excel文件
XSSFWorkbook excel = new XSSFWorkbook(in);
//获取Excel文件的第1个Sheet页
XSSFSheet sheet = excel.getSheetAt(0);
//获取Sheet页中的最后一行的行号
int lastRowNum = sheet.getLastRowNum();
for (int i = 0; i <= lastRowNum; i++) {
//获取Sheet页中的行
XSSFRow titleRow = sheet.getRow(i);
//获取行的第2个单元格
XSSFCell cell1 = titleRow.getCell(1);
//获取单元格中的文本内容
String cellValue1 = cell1.getStringCellValue();
//获取行的第3个单元格
XSSFCell cell2 = titleRow.getCell(2);
//获取单元格中的文本内容
String cellValue2 = cell2.getStringCellValue();
System.out.println(cellValue1 + " " +cellValue2);
}
//关闭资源
in.close();
excel.close();
}
}
1.设计Excel模板文件
2.查询近30天的运营数据
3.将查询到的运营数据写入模板文件
4.通过输出流将Excel文件下载到客户端浏览器