应价交易系统网站开发,网站开发推荐英文字体,最近的热点新闻事件,做网站要怎样加盟欧普重难点详解
1、定义全局异常 2、ThreadLocal
ThreadLocal 并不是一个Thread#xff0c;而是Thread的一个局部变量ThreadLocal 为每一个线程提供独立的存储空间#xff0c;具有线程隔离的效果#xff0c;只有在线程内才能取到值#xff0c;线程外则不能访问
public void …重难点详解
1、定义全局异常 2、ThreadLocal
ThreadLocal 并不是一个Thread而是Thread的一个局部变量ThreadLocal 为每一个线程提供独立的存储空间具有线程隔离的效果只有在线程内才能取到值线程外则不能访问
public void set(T value) 设置当前线程的线程局部变量的值public T get() 返回当前线程所对应的线程局部变量的值public void remove() 移除当前线程的线程局部变量注意客户端每次发送http请求对应的服务端都会分配一个新的线程在处理过程中涉及到系列方法属于同一个线程 【1】LoginCheckFilter的doFilter方法 【2】EmployeeController的update方法 【3】MyMetaObjectHandler的updateFill方法
3、BaseContext上下文 BaseContext是基于ThreadLocal类封装的工具类用于在同一线程中的封装数据和获取数据。 BaseContext工具类用于存放和取出当前登录的用户的idpublic class BaseContext {public static ThreadLocalLong threadLocal new ThreadLocal();/*** 设置当前线程的线程局部变量的值* param id*/public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}
4、PageHelper分页 pagehelper是mybatis 提供的分页插件 开始分页
PageHelper.startPage(1, 10)// selectlist查询数据库的时候会自动加上limit 110。在CategoryServiceImpl声明pageQuery方法及其父类接口 public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {// 分页器对象PageCategory page new Page();ListCategory categoryList categoryMapper.pageQuery(categoryPageQueryDTO);Long total page.getTotal();// 分页return new PageResult(total,categoryList);}
在EmployeeServiceImpl声明pageQuery方法及其父类接口
public PageResult pageQuery(EmployeePageQueryDTO dto) {PageHelper.startPage(dto.getPage(),dto.getPageSize());PageEmployee page employeeMapper.pageQuery(dto);return new PageResult(page.getTotal(),page.getResult());}原理:
Mybatis内置了分页拦截器PageInterceptor即在执行相关sql之前会拦截一些操作通过setLocalPage()方法将分页信息保存在当前线程中。分页查询方法与之处在同一个线程中共享ThreadLocal中的数据selectlist查询之后赋值给的List list。这个list是Page 类型再将list放到PageInfo中即可。
查询
ListEmployee list employeeMapper.selectByExample(Example);
分页结果展示 PageInfoEmployee pageInfo new PageInfo(list); System.out.println(总记录数pageInfo.getTotal()); System.out.println(总页数pageInfo.getPages()); System.out.println(一页的大小pageInfo.getSize());
5、日期按年月日显示
在 WebMvcConfiguration 中扩展Spring MVC的消息转换器统一对日期类型进行格式化处理 protected void extendMessageConverters(ListHttpMessageConverter? converters) {log.info(Spring MVC扩展消息转化器...);// 创建消息转换器对象MappingJackson2HttpMessageConverter messageConverter new MappingJackson2HttpMessageConverter();// 设置该消息转换器使用 JacksonObjectMapper 进行转换messageConverter.setObjectMapper(new JacksonObjectMapper());// 将消息转换器对象追加到 mvc 框架的转换器集合中(加到最前面)converters.add(0,messageConverter);}6、启用/禁用账号
/**
* 启用禁用员工账号
*/
Override
public void startOrStop(Integer status, Long id) {Employee employee Employee.builder().status(status).id(id).build();employeeMapper.update(employee);
}
Employee.builder().build()建造者模式builder构造对象Builder 注解
6、公共字段填充
mybatis-plus提供了公共字段自动填充功能
// 在EmployeeMapper
AutoFill(value OperationType.INSERT)
void insert(Employee employee);AutoFill(value OperationType.UPDATE)
void update(Employee employee);// CategoryMapper
AutoFill(value OperationType.INSERT)
void insert(Category category);AutoFill(value OperationType.UPDATE)
void update(Category category);
实现步骤 【1】实体类的属性上加入注解TableField
create_timecreate_user 使用 Insert
update_timeupdate_user 使用 Insert/update
FieldFill.DEFAULT //默认不自动填充ApiModelProperty(value 创建时间)TableField(fill FieldFill.INSERT)private LocalDateTime createTime;ApiModelProperty(value 更新时间)TableField(fill FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;
【2】元数据对象处理器实现MetaObjectHandler接口,
Slf4j
Component // 交给spring管理
public class MyMetaObjectHandler implements MetaObjectHandler {Overridepublic void insertFill(MetaObject metaObject) {log.info(start insert fill...);metaObject.setValue(createTime, LocalDateTime.now());metaObject.setValue(updateTime,LocalDateTime.now());metaObject.setValue(createUser, BaseContext.getCurrentId());metaObject.setValue(updateUser,BaseContext.getCurrentId());}Overridepublic void updateFill(MetaObject metaObject) {log.info(start update fill...);long id Thread.currentThread().getId();log.info(当前线程id:{},id);metaObject.setValue(updateTime,LocalDateTime.now());metaObject.setValue(updateUser,BaseContext.getCurrentId());}7、文件上传 PostMapping(/upload)ApiOperation(文件上传)public ResultString upload(MultipartFile file){log.info(文件上传: {}, file);try {// 原始文件名String originalFilename file.getOriginalFilename();// 截取原始文件名的后缀String suffix originalFilename.substring(originalFilename.lastIndexOf(.));// 构造新文件名称String objectName UUID.randomUUID().toString() extension;
// 文件的请求路径File dir new File(basePath);// 创建一个目录对象// 将临时文件转存到指定位置
file.transferTo(new File(basePathfileName));7、请求参数requestparam与requestbody
ResquestBody要搭配PostMapping使用ResquestParam要搭配GetMapping使用 区别equestparam与requestbody
【RequestParam】接收的参数是来自HTTP请求体或请求url的QueryString中
public void aliReceive(RequestParam(message) String message)RequestParam用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容
RequestParam 接受JSON的字符串
RequestParam注解无法读取application/json格式数据
【RequestBody】一般用来处理application/json、application/xml等类型的数据。
POST请求中通过HttpEntity传递的参数必须要在请求头中声明数据的类型Content-TypeSpringMVC通过使用
【PathVariable】
// 参数名和url变量名不一致
RequestMapping(/user/{id})
public String testPathVariable(PathVariable(id) String userId){System.out.println(路径上的占位符的值id);
}// 参数名和url变量名一致
RequestMapping(/getUser/{name})public User getUser(PathVariable String name){return userService.selectUser(name);}通过PathVariable例如/blogs/1
通过RequestParam例如blogs?blogId18、HttpClient
【发送请求步骤】
创建HttpClient对象创建请求对象HttpGet、HttpPost等请求对象调用HttpClient的execute方法发送请求
/*** 测试通过httpclient发送GET方式的请求*/
Test
public void testGET() throws Exception {// 创建httpclient对象CloseableHttpClient httpClient HttpClients.createDefault();// 创建请求对象HttpGet httpGet new HttpGet(http://localhost:8080/user/shop/status);// 发送请求接收响应结果CloseableHttpResponse response httpClient.execute(httpGet);// 获取客户端返回的状态码int statusCode response.getStatusLine().getStatusCode();System.out.println(服务端返回的状态码为 statusCode);HttpEntity entity response.getEntity();String body EntityUtils.toString(entity);System.out.println(服务端返回的数据为 body);// 关闭资源response.close();httpClient.close();
}
9、微信小程序登录
在application-dev.yml中写入具体的配置属性
skywechat:appid: ${sky.wechat.appid}secret: ${sky.wechat.secret}创建user/UserController创建微信登录的方法
PostMapping(/login)ApiOperation(微信登录)public ResultUserLoginVO login(RequestBody UserLoginDTO userLoginDTO){log.info(微信用户登录{},userLoginDTO);// 微信登录User user userService.wxLogin(userLoginDTO);// 为微信用户生成jwt令牌MapString, Object claims new HashMap();claims.put(JwtClaimsConstant.USER_ID, user.getId());String token JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);UserLoginVO userLoginVO UserLoginVO.builder().id(user.getId()).openid(user.getOpenid()).token(token).build();return Result.success(userLoginVO);
在UserServiceImpl中实现wxLogin的方法及其父类接口 // 微信服务接口地址public static final String WX_LOGIN https://api.weixin.qq.com/sns/jscode2session;
public User wxLogin(UserLoginDTO userLoginDTO) {String openid getOpenid(userLoginDTO.getCode());// 判断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);}private String getOpenid(String code){// 调用微信接口服务获取当前微信用户的openidMapString, String map new HashMap();map.put(appid, weChatProperties.getAppid());map.put(secret, weChatProperties.getSecret());map.put(js_code, code);map.put(grant_type, authorization_code);String json HttpClientUtil.doGet(WX_LOGIN, map);JSONObject jsonObject JSON.parseObject(json);String openid jsonObject.getString(openid);return openid;}
编写JwtTokenUserInterceptor拦截器校验用户端token是否是合法的
public class JwtTokenUserInterceptor implements HandlerInterceptor {...}在WebMvcConfiguration中注册拦截器 Autowired
private JwtTokenUserInterceptor jwtTokenUserInterceptor;protected void addInterceptors(InterceptorRegistry registry) {log.info(开始注册自定义拦截器...);registry.addInterceptor(jwtTokenAdminInterceptor).addPathPatterns(/admin/**).excludePathPatterns(/admin/employee/login);registry.addInterceptor(jwtTokenUserInterceptor).addPathPatterns(/user/**).excludePathPatterns(/user/user/login).excludePathPatterns(/user/shop/status);
10、Redis缓存
RedisTemplate是Spring Data Redis提供给用户的最高级的抽象客户端用户可直接通过RedisTemplate进行多种操作、异常处理、序列化、发布订阅等 ———————————————————— spring-data-redis的提供了如下功能
连接池自动管理提供了一个高度封装的“RedisTemplate”类进行了归类封装,将同一类型操作封装为operation接口
ValueOperations简单K-V操作 redisTemplate.opsForValue(). SetOperationsset类型数据操作 redisTemplate.opsForSet(). ZSetOperationszset类型数据操作 redisTemplate.opsForZSet(). HashOperations针对map类型的数据操作 redisTemplate.opsForHash() ListOperations针对list类型的数据操作 redisTemplate.opsForList().
针对数据的“序列化/反序列化”提供了多种可选择策略(RedisSerializer) JdkSerializationRedisSerializerPOJO对象的存取场景使用JDK本身序列化机制将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作最终redis-server中将存储字节序列。是目前最常用的序列化策略。 StringRedisSerializerKey或者value为字符串的场景根据指定的charset对数据的字节序列编码成string是“newString(bytes,charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。 JacksonJsonRedisSerializerjackson-json工具提供了javabean与json之间的转换能力可以将pojo实例序列化成json格式存储在redis中也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时需要明确指定Class类型因此此策略封装起来稍微复杂。 OxmSerializer提供了将javabean与xml之间的转换能力目前可用的三方支持包括jaxbapache-xmlbeansredis存储的数据将是xml工具。不过使用此策略编程将会有些难度而且效率最低不建议使用。【需要spring-oxm模块的支持】 11.BeanUtils
BeanUtils.copyProperties的用法
常见场景
接口中将前端请求参数xxVo转化为xxQuery对象查询数据库条件对象
BeanUtils.copyProperties(source,target);BeanUtils.copyProperties(要转换的类, 转换后的类);源对象source的属性拷贝值赋给目标对象target的过程中,属性名和属性类型都相同的属性才能被成功拷贝赋值做赋值的属性一定要有对应的setter/getter才能成功赋值1.对于类型为Boolean/Short/Integer/Float/Double的属性它会转换为0java.util.Date/BigDecimal/java.sql.Date/java.sql.Timestamp/java.sql.Time这几个类如果值为null则在copy时会抛异常需要使用对应的Conveter org.springframework.beans.BeanUtils BeanUtils.copyProperties(a, b)a复制到b org.apache.commons.beanutils.BeanUtilsBeanUtils.copyProperties(a, b)b复制到a
12、Spring Task定时处理
Spring Task 是Spring框架提供的任务调度工具
【Spring Task实现步骤】
导入maven左边启动类添加EnableScheduling注解开启任务调度自定义定时任务 Scheduled(cron ) Scheduled(cron 0 * * * * ? *) // 每分钟触发一次public void processTimeoutOrder(){log.info(定时处理超时订单{}, LocalDateTime.now());13、WebSocket WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手两者之间就可以创建持久性的连接 并进行双向数据传输 创建websocket/WebSocketServer实现WebSocket服务
Component
ServerEndpoint(/ws/{sid})
public class WebSocketServer {// 存放会话对象
private static MapString, Session sessionMap new HashMap();//连接建立成功OnOpenpublic void onOpen(Session session, PathParam(sid) String sid) {System.out.println(客户端 sid 建立连接);sessionMap.put(sid, session);}
//收到客户端消息OnMessagepublic void onMessage(String message, PathParam(sid) String sid) {System.out.println(收到来自客户端 sid 的信息: message);}
// 关闭连接OnClosepublic void onClose(PathParam(sid) String sid) {System.out.println(连接断开: sid);sessionMap.remove(sid);}
// public void sendToAllClient(String message) {CollectionSession sessions sessionMap.values();for (Session session : sessions) {try {//服务器向客户端发送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}创建WebSocketTask中通过WebSocket向客户端发送消息 public void sendMessageToClient() {webSocketServer.sendToAllClient(这是来自服务端的消息 DateTimeFormatter.ofPattern(HH:mm:ss).format(LocalDateTime.now()));}14、LambdaQueryWrapper
LambdaQueryWrapper是Mybatis-Plus框架中的一个查询条件构造器
LambdaQueryWrapperUser queryWrapper new LambdaQueryWrapper();
queryWrapper.eq(User::getName, 张三) // 等于eq.ne(User::getAge, 18) // 不等于ne.gt(User::getSalary, 5000) // 大于gt.like(User::getEmail, abc) //模糊查询.orderByDesc(User::getCreateTime);// 降序
ListUser userList userMapper.selectList(queryWrapper);
15、Nginx
反向代理允许Nginx服务器代表客户端将请求转发给后端的多个应用服务器
16、Spring Cache
Spring Cache 是一个框架实现了基于注解的缓存功能底层可以切换不同的缓存实现如Redis PostMappingApiOperation(value 新增套餐)CacheEvict(cacheNames setmealCache,key #setmealDTO.categoryId)public Result save(RequestBody SetmealDTO setmealDTO){setmealService.save(setmealDTO);}// 修改信息CacheEvict(cacheNames setmealCache,allEntries true)public Result update(RequestBody SetmealDTO setmealDTO){setmealService.update(setmealDTO);return Result.success();}常用注解
EnableCaching // 开启缓存注解功能启动类上Cacheable //在方法执行前查询缓存中是否有数据CachePut //将方法的返回值加入缓存中CacheEvict //删除缓存