标签:category product 缓存 spring boot key 微信 categoryType public
1、lombok工具
1.1、依赖 groupId:org.projectlombok;artifactId:lombok
1.2、idea 要安装lombok plugin
1.3、作用: 对model类加一个@Data注解就可以省写set and get方法
对类加@Slf4j注解可以直接通过log调用日志方法
对类加@Getter注解就可以省去写get方法
2、不要在for中有查询数据库行为,会影响性能
3、数据的更新,先查询出来,再通过set方法更新要更新的字段再将整个对象更新
4、@JsonProperty("name")注解VO层bean属性,可以重新指定返回前端的字段名
5、java8,lambda的作用:从对象List中获取某个字段并将其放入集合中
eg:List ageList = personList.stream().map(e->e.getAge()).collect(Collectors.toList());
eg:List contactList = personList.stream().map(e->
new Contact(e.getPhone(),e.getName())
).collect(Collectors.toList());
6、开发中常用到将model中的大部分属性set到vo对象中,可以使用BeanUtils.copyProperties(model,vo);
但要注意,如果model属性的值是null,也会copy过去。
7、判断是否为空:
7.1 集合:CollectionUtils.isEmpty({集合对象})
7.2 字符串:StringUtils.isEmpty({String})
8、controller下方法加参数BindingResult bindingResult, 可以通过bindingResult.hasErrors()判断参数校验是否有误。
9、使用Gson将json字符串转化为List对象:gson.fromJson({String},new TypeToken<{List}>(){}.getType());
10.JsonSerializer的作用:可以实现对对象属性值进行统一重写
用法:10.1 写一个class 继承 JsonSerializer<{对象属性类型}>
10.2 重写serialize方法,在方法中可以对属性值进行处理
10.3 在用到此重写的对象属性上使用注解:@JsonSerialize(using={类.class})
11、Page<{vo}>对象,vo->另外一个vo1的方法:
11.1 将List转成List:可以使用java8,lambda进行转换
11.2 Page <- new PageImpl({List},{Pageable},{List})
12、配置文件中值的获取:
12.1 @ConfigurationProperties(prefix=前缀):将配置文件中的值映射到一个bean的属性(可以为Map<String,String>())中
12.3 类中引用 @Autowired private Environment env; 通过 env.getProperty(“ms.db.username”)可以获取
13、微信微信开发:
13.1 第三方工具SDK:https://github.com/wechat-group/weixin-java-tools
13.2 第三方支付SDK:https://github.com/Pay-Group/best-pay-sdk
13.2 授权时如果提示redirect_uri参数错误,说明配置网页授权获取用户基本信息填写的域名不对
14、www.ibootstrap.cn 可以快速生成前端代码
15、枚举的更高级使用:视频的卖家-订单-controller(下)15:00
16、JSON接口注解:
16.1 @JsonIgnore:如果某个对象的属性不想出现在生成的json中,可以在属性上加上此注解
16.2 @JsonInclude(Include.NON_NULL)如果某个对象的属性值为null时,不想出现在生成的json中,可以在类上加上此注解
17、controller与service层,逻辑分工:如果与用户权限判断相关的逻辑,那就在controller进行,其他逻辑应以操作为单位,写在service层,方便重用
18、freeMarker
18.1 List语法:<#list 1..{num} as index></#list> 可以遍历出1到{num}之间的整数,常用于翻页
18.2 ${}内的变量可以进行运算
18.3 如果修改了模板内容,可以使用build project进行刷新,不需要重启
18.4 ${(值)!””}:意思是如果值拿不到,就显示””,值要加括号
18.5 html标签内可以嵌套freeMarker标签
19、@Bean注解的方法,在其它类中的引用:@Autowired private 方法返回类型 方法名
20、redis:使用时注意一定要设置过期时间
20.1 连接管理工具:redis desktop manager
20.2 依赖:spring-boot-starter-data-redis
20.3 参数配置:spring.redis.host=127.0.0.1;spring.port=6379(直接配置就行了,spring会自动去读取)
20.4 @Autowired private StringRedisTemplate redisTemplate(当然还可以使用其它类型模板)
20.5 redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECOND);
20.6 redisTemplate.opsForValue().getOperations().delete(key);
21、cookie:
21.1 设置:Cookie cookie = new Cookie(key,value);
cookie.setPath("/");
cookie.setMaxAge(7200);
response.addCookie(cookie);
21.2 获取:Cookie[] cookies = request.getCookies();
Cookie cookie1 = null;
for(Cookie cookie:cookies){
if(cookie.getName().equals({name})){
cookie1 = cookie;
}
}
21.3 清除:只要将过期时间设置为0
22、ModelAndView:
22.1 重定向时要使用完整的http地址 new ModelAndView("redirect:http://xxxx.xxx.cxx")
23、 aop
23.1 类加@Aspect注解
23.2 切入点:@Pointcut("execution(public * com.imooc.controller.Seller*.*(..)) && !execution(public * com.imooc.controller.SellerUserController.*(..))")
public void verify(){}
23.3 进行拦截
@Before("verify()") //指定切入点
public void doVerify(){
//1、获取requeste
ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//2、查询cookie,如果校验不通过就抛出异常(使用统一异常拦截处理)
//3、查询redis,如果校验不通过就抛出异常(使用统一异常拦截处理)
}
24、拼接
24.1 字符串的拼接可以使用concat({String})方法
25、消息类的异常,只打印日志,不要抛出(不然后影响到正常的逻辑)
26、webSocket服务端:
26.1 引入依赖:spring-boot-starter-websocket
26.2 ServerEndpointExporter注入ioc容器:
@Component
public class WebSocketConfig{
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
26.3 WebSocket
@Component
@ServerEndpoint("/WebSocket")
public class WebSocket{
private Session session;
private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session){
this.session = session;
webSocketSet.add(this);
}
@OnClose
public void onClose(){
webSocketSet.remove(this);
}
@OnMessage
public void onMessage(String message){
System.out.println("收到客户端发来的消息:"+message);
}
public void sendMessage(String message){
for(WebSocket webSocketSet : webSocketSet){
try{
webSocket.sesion.getBasicRemote().sendText(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
27、异常使用心得:
27.1 根据不同业务定义对应的异常(要继承 RuntimeException),行参类型使用枚举
27.2 有异常直接抛出
27.3 处理:对于返回json的接口,使用@ControllerAdice,@ExceptionHandler(value=定义好的异常类.class)
对于返回页面的路由,使用try{}catch(){}的方法进行捕获
28、mybatis的使用:
28.1 引入依赖:mybatis-spring-boot-starter(1.2.0)
28.2 在主启动类中添加@MapperScan(basePackages="com.imooc.dataobject.mapper")//mapper接口所在的包
28.3 在com.imooc.dataobject.mapper包下创建接口类
28.4 设置日志级别为:trace
logging.level.com.imooc.dataobject.mapper = trace//否则就无法看到正确查询时的sql语句
28.5.1 map方式写入
@Insert("insert into product_category(category_name,category_type) values(#{categoryName,jdbcType=VARCHAR},#{categoryType,jdbcType=INTEGER})")
int insertByMap(Map<String,Object>);
28.5.2 对象方式写入
@Insert("insert into product_category(category_name,category_type) values(#{categoryName},#{categoryType})")
int insertByObject(ProductCategory productCategory);
28.5.3 查询
@Select("select * form product_category where category_type = #{categoryType}")
@Results({
@Result(colum = "category_id",property= "categoryId"),
@Result(colum = "category_name",property= "categoryName"),
@Result(colum = "category_type",property= "categoryType")
})
ProductCategory findBycategoryType(Integer categoryType);
28.5.4 某些字段更新
@Update("update product_category set category_name =#{categoryName} where category_type=#{categoryType}")
int updateByCategoryType(@Parm("categoryName") String categoryName,@Parm("categoryType")Integer categoryType );
28.5.5 对象更新
@Update("update product_category set category_name =#{categoryName} where category_type=#{categoryType}")
int updateByObject(ProductCategory productCategory );
28.5.6 删除
@Delete("delete from product_category where category_type=#{categoryType}")
int deleteByCategoryType(Integer categoryType);
28.6 xml例子:
28.6.1 在resources 下建一个mapper包,再在mapper下建xml文件
28.6.2 配置mybatis.mapper-locations=classpath:mapper/*.xml
29、JPA 与 MyBatis都要注意:
29.1 建表时用sql,不用JPA建表
29.2 表与表之间的关系使用软关联,慎用@oneToMany和@ManyToOne
30、压测工具:Apache ab
30.1 ab -n 100 -c 100 网址 (-n 100 表示 100 个请求,-c 100 表示 100 个并发)
30.2 ab -t 60 -c 100 网址 (-t 60 表示 60秒内不停地请求,-c 100 表示 100 个并发)
31、并发:
31.1 使用Synchronized 可以保证数据线程安全,但速度会慢,无法做到细粒度控制,只适合单点的情况
31.2 使用redis分布式锁(因为redis是单线程的):用到的命令:SETNX(key已存在就什么也不做,若key不存在就更新),GETSET(先取出值,将更新)
31.2.1 加锁/解锁方法:
@Component
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 加锁
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key,String value){
if(redisTemplate.opsForValue().setIfAbsent(key,value)){
return true;
}
//currentValue =A ,两个线程的value都是B,其中一个线程拿到锁
String currentValue = redisTemplate.opsForValue().get(key);
//如果锁过期
if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue)<System.currentTimeMillis()){
//获取上一个锁的时间
String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
if(!StringUtils.isEmpty(oldValue) &&oldValue.equals(currentValue)){
return true;
}
}
return false;
}
public void unlock(String key,String value){
try{
String currentValue = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【redis分布式锁】解锁异常,{}",e.getMessage());
}
}
}
32、缓存:
32.1 启动类加@EnableCaching//如果不存在,就引入依赖spring-boot-starter-cache
32.2 对要使用缓存的方法加@Cacheable(cacheNames="product",key="123")
32.2.1 属性cacheNames:缓存key的前缀
32.2.2 属性key:缓存key,可以动态赋值key="#参数",eg:key = "#productId"
32.2.3 属性condition:条件判断,成立时才缓存,eg:condition = "#productId.length()&10"
32.2.4 unless:条件,如果不,eg:unless = "#result.getCode!=0)//只有在返回结果的code为0时才进行缓存,#result可以代替方法的返回对象
32.3 对触发更新缓存的方法加@CachePut(cacheNames="product",key="123")//会将key相同的(包括前缀)的缓存值更新(要求方法的返回对象与使用缓存的方法的返回对象相同)
32.4 对触发清空缓存的方法加@CacheEvict(cacheNames="product",key="123")//会将key相同的(包括前缀)的缓存清空(方法的返回对象可以与使用缓存的方法的返回对象不同)
32.5 对类加@CacheConfig(cacheNames="product")//这个类的方法如果使用缓存,则前缀都为product
32.6 注意:要缓存的对象一定继承可序列化类
33、项目部署
33.1 多环境配置:application-dev.yml application-prod.yml application.yml(spring.profiles.active=dev)//默认是选择dev
33.2 打包 mvn clean packsge -Dmaven.test.skip=true
33.3 临时启动 java -jar -Dserver.port=8080 -Dspring.profiles.active=prod sell.jar
33.4 后台启动 nohup java -jar -Dserver.port=8080 -Dspring.profiles.active=prod sell.jar && /data/logs/didafenqi/didafenqi-api/log.out &
33.5 service方式启动
33.5.1内容:sell.service(放在/etc/systemd/system/下)
[Unit]
Description=sell
After=syslog.target network.target
[Service]
Type=StringRedisTemplate
ExecStart=/usr/bin/java -jar -Dserver.port=8080 -Dspring.profiles.active=prod sell.jar
ExecStop=/bin/kill -15 $MAINPID
User=root
Group=root
[Install]
WantedBy=multi-user.target
33.5.2启动命令 systemctl start sell
33.5.3关闭命令 systemctl stop sell
33.5.4开机启动 systemctl enable sell
33.5.5取消开机启动 systemctl disable sell
标签:category,
product,
缓存,
spring,
boot,
key,
微信,
categoryType,
public
From: https://www.cnblogs.com/anquing/p/17603513.html