项目中遇到的错误以及解决方案二

124 阅读3分钟

一、如何修改controller返回值

1、
在springboot中可以通过实现ResponseBodyAdvice接口,并配合@ControllerAdvice注解,实现
该接口主要有两个方法:supports()和beforeBodyWrite()方法,
只有当supports()方法返回值为true时才会执行beforeBodyWrite()方法,
该方法返回值就是返回前端的值

2、
通过实现拦截器HandlerInterceptor,在postHandler方法中通过ModelAndView类实现

二、使用springboot+websocket发消息

1、引入websocket依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、自定义webSocketSession管理类,用于统一管理客户端

public class WebSocketSessionManger {
    private static ConcurrentHashMap<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();

    public static void add(String sessionId, WebSocketSession webSocketSession){
        sessionMap.put(webSocketSession.getId(),webSocketSession);
    }
    public static WebSocketSession get(String sessionId){
        return sessionMap.get(sessionId);
    }
    public static WebSocketSession remove(String sessionId){
        return sessionMap.remove(sessionId);
    }

    public static void removeAndClose(String sessionId){
        WebSocketSession session = remove(sessionId);
        if(session!=null){
            IoUtil.close(session);
        }
    }

    //单独发送消息
    public static void sendMessage(String sessionId,String message){
        WebSocketSession session = get(sessionId);
        if(session!=null){
            try {
                session.sendMessage(new TextMessage(message));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //群发消息
    public static void broadcast(String message){
        sessionMap.forEach((sessionId,session)->{
            sendMessage(sessionId,message);
        });
    }
}

3、自定义websocket处理器,实现WebSocketHandler接口,自定义处理客户端消息

public class TestSocketHandler implements WebSocketHandler {
    Logger logger = LoggerFactory.getLogger(TestSocketHandler.class);
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        logger.info("socket连接成功,sessionId:{}",webSocketSession.getId());
        WebSocketSessionManger.add(webSocketSession.getId(),webSocketSession);
    }

    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        if(webSocketMessage instanceof TextMessage){
                String payload = (String) webSocketMessage.getPayload();
                logger.info("收到消息:{}",payload);
            }else{
                logger.error("只接受文本信息:sessionId:{}",webSocketSession.getId());
            }
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        logger.error("socket 处理异常,sessionId:{},异常原因:{}",webSocketSession.getId(),throwable.getMessage());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        logger.info("socket断开,sessionId:{}",webSocketSession.getId());
        //移除链接并,关闭session
         WebSocketSessionManger.removeAndClose(webSocketSession.getId());
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}

4、自定义websocket配置类,初始化websocket

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        //注册websocketHandler处理器,以及访问地址
        registry.addHandler(testSocketHandler(), "/ws/test")
                .setAllowedOrigins("*");
    }


    @Bean
    public WebSocketHandler testSocketHandler() {
        return new TestSocketHandler();
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean factoryBean = new ServletServerContainerFactoryBean();
        //设置消息缓冲区大小
        factoryBean.setMaxTextMessageBufferSize(8192);
        factoryBean.setMaxBinaryMessageBufferSize(8192);
        return factoryBean;
    }

    //避免与spring创建的 taskScheduler冲突
    @Bean
    public TaskScheduler taskScheduler(){
        ThreadPoolTaskScheduler poolTaskScheduler = new ThreadPoolTaskScheduler();
        poolTaskScheduler.setPoolSize(10);
        poolTaskScheduler.initialize();
        return poolTaskScheduler;
    }
}

5、自定义json序列化器

继承jackson的JsonSerializer实现自定义json序列化器,代码如下:

//自定义化序列器
public class CustomSerializer extends JsonSerializer<String> implements ContextualSerializer {

    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if(StringUtils.isNotEmpty(s)) {
            jsonGenerator.writeString(DesensitizedUtil.password(s));
        }else{
            jsonGenerator.writeString(s);
        }
        System.out.println(value);
    }
    private String value;
    public CustomSerializer(){}

    public CustomSerializer(String value){
        this.value = value;
    }
    //实现ContextualSerializer接口,获取属性上的指定注解
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        FieldAnomalymize annotation = beanProperty.getAnnotation(FieldAnomalymize.class);
        if(annotation!=null){
            return new CustomSerializer(annotation.value());
        }
        return this;
    }
}

//自定义注解
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
//序列化
@JsonSerialize(using = CustomSerializer.class)
public @interface FieldAnomalymize {
   String value() default "";
}

Apache Tika解析文件内容

1、在pom文件中引入

<!--2.11以上-->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.15.0</version>
</dependency>
<!--尽量使用最新的-->
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-core</artifactId>
    <version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-parsers-standard-package -->
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-parsers-standard-package</artifactId>
    <version>2.9.2</version>
</dependency>

2、使用实例如下

private static void extracted1(String str2) throws IOException {
    Tika tika = new Tika();
    //检测文件的MediaType类型
    String detect = tika.detect(new File(str2));
    System.out.println(detect);
}

private static void extracted(String str2) {
    File file = new File(str2);
    //Hutool工具类自动转成kb,mb等字符串
    String size = DataSizeUtil.format(file.length());
    //使用自动检测解析提取文件内容
    //可自定义Parser解析器
    AutoDetectParser parser = new AutoDetectParser();

    //ContentHandler用于处理文件内容,将其解析成不同的格式
    //文本格式
    //BodyContentHandler handler = new BodyContentHandler();
    //html格式
    //ToHTMLContentHandler handler = new ToHTMLContentHandler();
    BodyContentHandler handler = new BodyContentHandler();
    Metadata metadata = new Metadata();
    try(FileInputStream fileInputStream = new FileInputStream(file)){
          parser.parse(fileInputStream,handler,metadata);
        System.out.println(handler.toString());
        //获取元数据名称及值
        for (String name : metadata.names()) {
            System.out.println(name+":"+metadata.get(name));
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (TikaException e) {
        throw new RuntimeException(e);
    } catch (SAXException e) {
        throw new RuntimeException(e);
    }
}

public static void parseFile(String str){
    File file = new File(str);
    Tika tika = new Tika();
    try(FileInputStream fileInputStream = new FileInputStream(file)){
        String content = tika.parseToString(fileInputStream);
        System.out.println(content);
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (TikaException e) {
        throw new RuntimeException(e);
    }
}