# community
**Repository Path**: lsua/community
## Basic Information
- **Project Name**: community
- **Description**: Springboot论坛项目
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2020-08-31
- **Last Updated**: 2023-02-06
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
### 自定义注解检查登录状态
1.编写一个注解类
```java
package com.ls.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}
```
2.编写拦截器,拦截使用该注解的方法
```java
package com.ls.controller.interceptor;
import com.ls.annotation.LoginRequired;
import com.ls.util.CommunityUtil;
import com.ls.util.UserContextHolder;
import com.ls.util.UserContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* 拦截加了自定义注解 @LoginRequired 的请求
*/
@Component
public class LoginRequiredInterceptor implements HandlerInterceptor {
@Autowired
UserContextHolder hostHolder;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 判断拦截到的是否是方法
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 获取 @LoginRequired 注解
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
String xRequestedWith = request.getHeader("x-requested-with");
// 需要登录,用户没有登录
if (loginRequired != null && hostHolder.getUser() == null) {
if ("XMLHttpRequest".equals(xRequestedWith)) { // 如果是异步请求
response.setContentType("application/plain;charset=utf-8");
response.getWriter().write(CommunityUtil.getJSONString(302, "您还未登录,请登录!"));
} else {
response.sendRedirect(request.getContextPath() + "/toLogin");
}
return false;
}
}
return true;
}
}
```
3.到mvc配置类注册拦截器
```java
package com.ls.config;
import com.ls.controller.interceptor.AlphaInterceptor;
import com.ls.controller.interceptor.LoginRequiredInterceptor;
import com.ls.controller.interceptor.LoginTicketInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AlphaInterceptor alphaInterceptor;
@Autowired
private LoginTicketInterceptor loginTicketInterceptor;
@Autowired
private LoginRequiredInterceptor loginRequiredInterceptor;
// 拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(alphaInterceptor)
// .excludePathPatterns("/**/*.css","/**/*.js","/**/*.jpg","/**/*.jpeg","/**/*.png")
// .addPathPatterns("/");
// 注册拦截器 拦截除静态资源的所有请求
registry.addInterceptor(loginTicketInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.jpg","/**/*.jpeg","/**/*.png");
registry.addInterceptor(loginRequiredInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.jpg","/**/*.jpeg","/**/*.png");
}
}
```
Mybatis允许使用`foreach`标签对集合进行遍历,遍历ids,结果为以"("开始,每一项为id,间隔符为",",以")"结尾.
```sql
update community.message
set status = #{status}
where id in
#{id}
```
### 统一处理异常
表现层处理异常
把错误页面放到templates目录下的error目录里面,用对应的错误命名页面,Springboot就会自动跳转到发生对应错误状态的页面。
* @ControllerAdvice
用于修饰类,表示该类是Controller的全局配置类。
在此类中,可以对Controller进行如下三种全局配置:异常处理方案、绑定数据方案、绑定参数方案。
* @ExceptionHandler
用于修饰方法,该方法会在Controller出现异常后被调用,用于处理捕获到的异常。
* @ModelAttribute
用于修饰方法,该方法会在Controller方法执行前被调用,用于为Model对象绑定参数。
* @DataBinder
用于修饰方法,该方法会在Controller方法执行前被调用,用于绑定参数的转换器。
```java
@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice {
private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);
// 用于修饰方法,该方法会在Controller出现异常后被调用,用于处理捕获到的异常。
@ExceptionHandler({Exception.class})
public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.error("服务器发生异常: " + e.getMessage());
for (StackTraceElement element : e.getStackTrace()) {
logger.error(element.toString());
}
String xRequestedWith = request.getHeader("x-requested-with");
if ("XMLHttpRequest".equals(xRequestedWith)) { // 异步请求
response.setContentType("application/plain;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write(CommunityUtil.getJSONString(500, "服务器异常"));
} else {
// 重定向到错误页面
response.sendRedirect(request.getContextPath() + "/error");
}
}
}
```
### 统一处理日志
AOP概念
* Aspect Oriented Programing,即面向方面(切面)编程。
* AOP是一种编程思想,是对OOP的补充,可以进一步提高编程的效率。

AOP的实现
* Aspectj
* Spring AOP
Spring AOP
* JDK动态代理
java提供的动态代理技术,可以在运行时创建接口的代理实例。
Spring AOP默认采用此方式,在接口代理实例中织入代码。
* GGLib动态代理
采用底层的字节码技术,在运行时创建子类代理实例。
当目标对象不存在接口时,Spring AOP会采用此种方式,在子类实例中织入代码。
```java
@Component
@Aspect
public class ServiceLogAspect {
private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
// 切入点
@Pointcut("execution(* com.ls.service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
// 用户(ip)[1.2.3.4],在(时间)[xxx],访问了[com.nowcoder.community.service.xxx()].
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String requestURI = request.getRequestURI();
String ip = request.getRemoteHost();
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now().withNano(0);
String now = date + " " + time;
String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
logger.info("访问了" + requestURI); // 打印url
logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));
}
}
```
## 4
### 4.1 Redis入门
Springboot整合redis
导入包
```xml
org.springframework.boot
spring-boot-starter-data-redis
```
配置redis
```properties
# RedisProperties
spring.redis.database=11
spring.redis.host=localhost
spring.redis.port=6379
```
写redis配置类
```java
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置key的序列化方式
template.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式
template.setValueSerializer(RedisSerializer.json());
// 设置hash的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
}
}
```