# dev-suggestions **Repository Path**: maizdotme/dev-suggestions ## Basic Information - **Project Name**: dev-suggestions - **Description**: 项目相关技术积累 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 17 - **Forks**: 2 - **Created**: 2020-04-02 - **Last Updated**: 2023-03-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # feign的GET转为了POST https://blog.csdn.net/qq_34129814/article/details/107935091 ## 流程图的画法 https://zhuanlan.zhihu.com/p/67533900 ## vue脚手架SPA项目的登录页面分离及登录拦截实现 vue-router跳转及登录问题 需求: - 项目启动时的进入登录页,无导航条 https://www.jianshu.com/p/6f40ec034c5a - 登录成功后自动跳转到首页 https://blog.csdn.net/qq_30114149/article/details/78416457 - 如果没有登录不论输入任何路径都跳转到登录页 需要用到的知识点: - 子路由 (children) - 编程跳转页面(this.$router.push()) - 路由守卫(router.beforeEach()) App.vue只放router-view ```vue ``` 路由配置里默认跳转到 /login (1)处 ```javascript import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' import Product from '../views/Product.vue' import Login from '@/views/Login.vue' Vue.use(VueRouter) const routes = [ { path: '/', //(1) redirect:'/login' }, { path: '/login', name: 'login', component: Login }, { path: '/home', name: 'Home', component: Home, //(2) 设置子路由 children:[ { path: '/product', name: 'Product', component: Product }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') } ] }, ] const router = new VueRouter({ routes }) export default router ``` 编写登录逻辑,登录成功后在localStorage中存储一个登录标记,并跳转, ```vue ``` Home页面存在一个子路由,有router-view,配置见上面路由配置(2)处 ``` 没有登录不能访问的逻辑在main.js中,使用的是vue-router的导航守卫功能 //路由守卫,在跳转前检查是否登录,如果没有登录则跳转到登录 //详见 https://router.vuejs.org/zh/guide/advanced/navigation-guards.html router.beforeEach((to, from, next) => { let isAuthenticated = localStorage.getItem('isLogin')=='true'; console.log(to.path !== '/login' && !isAuthenticated) if (to.path !== '/login' && !isAuthenticated) { alert('您还没有登录,请先登录'); console.log('未登录,跳转登录页') next({ path:'/login' }) } else { next() } }); ``` 具体代码请见 [vue-login](vue-login) ## ElementUI上传多个文件的DEMO 代码在: front 是前端项目 代码在HelloWorld.vue中 src 是后端代码 主要是controller中的UploadController 运作模式是,前端默认会自动上传到action指定的路径,成功后回调on-success指定的函数 源码参考 :[multi-files-upload](multi-files-upload) 前端:[HelloWorld.vue](multi-files-upload/front/src/components/HelloWorld.vue) 后端:[UploadController](multi-files-upload/src/main/java/com/woniuxy/multifilesupload/controller/UploadController.java) ## 发送任意短信内容 国内短信有内容限制,可以使用国外的[twilio](https://twilio.com)试用(可以发大概50条短信),缺点是界面全英文 1. 参考 http://uuxn.com/twilio-toll-free-sms 注册账号 2. 试用模式下,twilio只能给验证过的手机号发短信,比如你自己的,在页面右端有个 “[verified numbers](https://www.twilio.com/console/phone-numbers/verified).” 的链接,点击可以添加手机号,添加时会发验证码验证 3. 以下是封装的工具类,请注意替换关键信息 ```java import com.twilio.Twilio; import com.twilio.rest.api.v2010.account.Message; import com.twilio.type.PhoneNumber; /** * * 使用twilio发送短信 */ public class SmsUtil { // 从这里 twilio.com/user/account 找以下内容 public static final String ACCOUNT_SID = "你的SID"; public static final String AUTH_TOKEN = "你的验证token"; //在twilio的个人页面上获取的trail number +12077460991 public static final String TRIAL_PHONE_NUMBER="你的试用手机号"; public void send(String to,String text){ Twilio.init(ACCOUNT_SID, AUTH_TOKEN); Message message = Message.creator(new PhoneNumber(to), new PhoneNumber(TRIAL_PHONE_NUMBER), text).create(); } } ``` ## controller层打印日志 参考[WebLogAspect.java](./WebLogAspect.java) ,代码依赖于AOP所以使用时需要 1)在pom中加入 ```xml org.springframework.boot spring-boot-starter-aop ``` 2)在Application启动类上加注解`@EnableAspectJAutoProxy` ## 跨域访问时session失效 前后端分离后,前端和后端运行在不同的域(ip+端口不同,生产是域名不同)下,而 浏览器因为安全限制无法获得跨域的cookie。 临时解决方案,前后端设置放行跨域cookie;真正的解决方案是通过JWT保持登录信息,session中保存的信息放到redis中; 临时解决方案具体做法: 1. 前端:每次ajax请求时设置一个`withCredentials` 的头,axios用法 ```javascript send2() { axios.defaults.withCredentials = true;//☆这句设置头 //发送请求 axios.get("http://localhost:8080/testSession2") .then(resp => { console.log(resp); this.remoteValue=resp.data.data; }).catch(err => { console.log(err); }) } ``` 2. 后端:新建一个webmvc配置类,配置cors跨域配置 ```java package com.woniuxy.sessiontest.config; import org.springframework.stereotype.Component; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Component public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedHeaders("*") .allowedMethods("POST","GET") .allowCredentials(true) .allowedOrigins("*"); } } ``` 3.此外,需要关闭chrome的一些特性 注意,chrome版本80之后默认开启了sameSite属性,导致cookie仍然无法获取,测试环境下建议: 将 chrome://flags/ 下的 SameSite by default cookies 设置为Disabled Cookies without SameSite must be secure 设置为Disabled 源码参考: 前端:[Home.vue](sessiontest/sessiontest-front/src/views/Home.vue) 后端参考:[WebConfig.java](sessiontest/src/main/java/com/woniuxy/sessiontest/config/WebConfig.java) 参考: https://www.jianshu.com/p/13d53acc124f ## 好用的工具类推荐 hutool: https://gitee.com/loolly/hutool [文档]( https://www.hutool.cn/docs/index.html#/ ) guava: http://ifeve.com/google-guava/ apache-commons: https://blog.csdn.net/leaderway/article/details/52387925 ## maven私服使用方式 参见:~[maven私服使用方式](./maven-private-repo.md)~ 使用云效代替本地maven私服,详情参考[云效使用方式](./yunxiao.md) ## Excel文件导出使用哪个库? POI支持比较全 JXL比较简便好用,建议使用JXL ## uniapp支付宝SDK支付失败问题 支付宝的沙箱账号不支持在sdk支付,uniapp无法突破 可以使用这个插件 https://ext.dcloud.net.cn/plugin?id=1728 ## Jackson日期时间少了几个小时问题 jackson反序列化是默认使用的是默认时区, ```java public final static String DEFAULT_TIMEZONE = "##default"; ``` 解决方案, 可以在每个字段加 ```java @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") ``` 但太累了,建议在application.properties中配置一下,全局有效,不需要每个字段配置@DateTimeFormat: spring.jackson.date-format=yyyy-MM-dd HH:mm spring.jackson.time-zone=GMT+8 ## 根据视频教程,访问elasticsearch时报类型错误 因为视频教程使用的es版本与 最新的spring-boot-starter-data-elasticsearch版本不一致。降低版本实现。 ```xml 1.8 6.8.4 org.springframework.boot spring-boot-starter-data-elasticsearch 2.2.1.RELEASE org.springframework.data spring-data-elasticsearch 3.2.1.RELEASE .... ``` ## vue的post请求参数,后端获取不到问题 因为vue的axios默认发送的是json格式,可以有两个方式解决, 1)在接受时使用 对参数使用 @RequestBody 提供一个对象接受所有参数 2)在发送的js代码中使用 qs 序列化一下 https://blog.csdn.net/weixin_41829196/article/details/85986331 ### 移动端API请求在服务端无法得到用户信息 现象:登录后,App发送的请求,Controller处理时,从shiro的subject得到User为null 错误原因:app无法存储cookie,无法提供sessionId,服务端的session关联不到,直接出错。 解决方案:使用JWT登录成功后返回token,在APP端存储下来(uniapp有存储的[API](https://uniapp.dcloud.io/api/storage/storage?id=setstorage)) 参考:https://learnku.com/articles/43682 ## 数据库设计注意点 1. 一对多或者多对一,关联存在多一方;多对多建关联表。 2. 一对一考虑能不能合并,根据业务判断; 3. 适当冗余,例如购物车可以冗余商品图片和名字,不用再关联查询商品表 4. 考虑加索引 5. 考虑支付退款等资金流程的表设计 6. 考虑接入各种API时的数据异常处理,比如,通知结果存储,操作失败后的重试等 ## 验证码 免费体验2万次验证量 https://open.captcha.qq.com/product.html?ADTAG=capt.head ## 客服机器人 https://cloud.tencent.com/solution/service ## 微信开发 微信开发SDK https://github.com/foxinmy/weixin4j ## 内容审核 https://www.qiniu.com/products/censor ## 全文搜索 推荐[elasticsearch](https://www.elastic.co/cn/) 数据同步用logstash ## 图片上传 场景:上传头像,然后在页面上显示出来 问题:上传到哪个位置?如何在页面上显示出来? 错误解决方案:上传到项目目录下,直接可以显示。问题在于部署环节,项目文件会覆盖,比如第一次部署过后,上传数据在该项目文件夹下,第二次部署时覆盖,则之前上传的数据丢失了。 正解: 1. 使用图床,直接上传到公开的图床,比如https://sm.ms 2. 使用Nginx,将图片上传至某个目录(如,d://upload/),然后通过Nginx将该目录代理成网络路径,直接可以通过完整的路径访问该图片,假设ng运行在8000端口,图片名为abc.jpg,则经过配置,可以使用http://localhost:8000/abc.jpg访问到这张图片 3. 使用oss服务器,专门用来存储小对象的,不过貌似得花钱,[参看阿里云](https://cn.aliyun.com/product/oss) 比如七牛云(免费每月10G流量) 具体参看:[七牛云上传文件](./qiniu.md) ,例子参看[demo](./devsuggestions) [注册链接](https://portal.qiniu.com/signup?code=1h5npa9r5az4i) ## 分布式定时任务 详细请参考[定时任务章节](./定时任务.md) 方案1. spring提供的定时任务注解,操作简单,参考[文章](http://www.ityouknow.com/springboot/2016/12/02/spring-boot-scheduler.html) 优势:集成简单 缺陷: 分布式环境下会出现并发问题,重复执行,比如同一个应用部署了两台机器时,会出现同时在8:00执行一个定时任务,那么就会执行两次定时,这时就需要调度。粗糙的解决方案是加锁,同时只允许一个执行,代码再进行一个状态判断,就不会造成反复执行,可以使用redis或者数据库都可以加锁。 方案2. 较为简单的场景,比如订单过期取消,可以使用rabbitmq的死信队列实现,[参考文章](https://www.jianshu.com/p/986ee5eb78bc) 或者 使用redis的[key过期事件驱动](https://www.cnblogs.com/owenma/p/10419896.html) 优势:实现较为简单 缺陷:应用场景有限 方案3. xxl分布式定时任务中间件 [仓库地址](https://gitee.com/xuxueli0323/xxl-job) 细节待研究 优势:生产级,成熟,功能丰富 缺陷:需要独立部署,有一定学习成本 ## 推送 uniapp的push功能 ``` 1. 开通个推、各厂商推送,获得id等配置信息 2. 开通unipush https://ask.dcloud.net.cn/article/35622 3. 服务端推给个推 http://docs.getui.com/getui/server/java/summary/ https://www.dcloud.io/docs/a/unipush/java.pdf 4. 客户端接入 https://ask.dcloud.net.cn/article/35726 ``` ## 即时聊天 方案1.websocket或者轮询 手动实现,UI可以参考[这个uniapp模板](https://ext.dcloud.net.cn/plugin?id=324) 缺陷:所有功能手动实现,很多细节处理不好 方案2.环信IM等第三方即时通信服务(李丰弟在尝试集成,已经完成接入) 缺陷:初期学习成本较高 ## 提交多个参数 提交的参数是一个集合,比如一天安排多个景点,则景点名字相同,都需要提交到后台。 参考 https://gitee.com/maizdotme/dev-suggestions/blob/master/devsuggestions/src/main/resources/static/batchAdd.html 解决方案 1.使用[]语法,springMVC会自动映射,参考 https://blog.csdn.net/u011781521/article/details/77586688 2.使用json传递数据,springMVC通过@RequestBody自动映射 参考https://blog.csdn.net/achenyuan/article/details/81114517