有关@EnableWebMvc
打开@EnableWebMvc查看官方注释,:
* Adding this annotation to an {@code @Configuration} class imports the Spring MVC
* configuration from {@link WebMvcConfigurationSupport}, e.g.:
意思就是这个标签注释与@Configuration一起使用,注释在springMvc的配置类上以配置自己需要的springMvc配置
* <p>To customize the imported configuration, implement the interface
* {@link WebMvcConfigurer} and override individual methods, e.g.:
这段和上面意思差不多,它实现了WebMvcConfigurer接口,可以通过override很简单的重写原来的配置,至于@EnableWebMvc应该是可注释可不注释
* <p>If {@link WebMvcConfigurer} does not expose some more advanced setting that
* needs to be configured consider removing the {@code @EnableWebMvc}
* annotation and extending directly from {@link WebMvcConfigurationSupport}
* or {@link DelegatingWebMvcConfiguration}, e.g.:
这段意思就是如果WebMvcConfigurer提供的方法不够用了,可以继承DelegatingWebMvcConfiguration或WebMvcConfigurationSupport并且移除@EnableWebMvc
这三段注释看起来解释的都是一件事,@EnableWebMvc作用:声明被注释类是配置类,并且导入DelegatingWebMvcConfiguration类,很简单,而且实际开发中我们经常使用的WebMvcConfigurer接口并不需要注册@EnableWebMvc也能使用; 它主要关键在于导入DelegatingWebMvcConfiguration类上,这个类它是WebMvcConfigurationSupport的子类,而自动配置类中有这样一段注释:
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 缺少WebMvcConfigurationSupport类自动注释才会生效,也就是说当我们在配置类上注释了@EnableWebMvc时,自动配置就没了!这一点对那些对spring框架不了解的程序员来说十分不友好,尤其是springBoot框架下,什么静态资源失效,什么映射找不到,那都是家常便饭; 所以如果除非是特殊情况下,最好不要在配置类上注释@EnableWebMvc,其实这个注释现在也基本不用了,如果要简单重写配置,实现WebMvcConfigurer接口即可,@EnableWebMvc加上与否决定是否屏蔽@EnableAutoConfiguration,如果WebMvcConfigurer提供的设置不够,直接继承WebMvcConfigurationSupport类即可,无论加不加@EnableWebMvc接口,都会屏蔽@EnableAutoCongfiguration
WebSocket
webSocket是一种支持后端主动与前端通信的协议,它有两种实现方式: 纯注解方法: (1)将ServerEndpointExporter实例注入到spring容器进行管理
@Configuration
public class webSocketConfig {
}
(2) 实现消息处理类,前后端的通过socket发送接收的消息都在这个类里处理
手动配置方法(老框架使用): (1)消息处理类,同第一种方法的(2)
@Component
public class MySocketHandler extends TextWebSocketHandler {
private static ConcurrentHashMap<String,WebSocketSession> map =
new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
map.put((String)session.getAttributes().get("id"), session);
System.out.println("已经有一个客户端连接,当前连接数:"+ map.size());
super.afterConnectionEstablished(session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("接收到客户端发来的消息,"+(String)session.getAttributes().get("id")+"消息为:"+ message.getPayload());
super.handleTextMessage(session, message);
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("客户端"+(String)session.getAttributes().get("id")+"出错");
super.handleTransportError(session, exception);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("已经有一个客户端退出,退出客户端为"+(String)session.getAttributes().get("id")
+ ",当前连接数:"+ map.size());
super.afterConnectionClosed(session, status);
}
}
afterConnectionEstablished对应@OnOpen,handleTextMessage对应@OnMessage,handleTransportError对应@OnError,afterConnectionClosed对应@OnClose
(2)拦截器,用于拦截客户端发起的连接请求以及后续的消息
public class MySocketIntercepter implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
HttpServletRequest rq2 = ((ServletServerHttpRequest) request).
getServletRequest();
String id = rq2.getParameter("id");
attributes.put("id", id);
return true;
}
System.out.println("websocket连接已经映射到,拦截器取值出错");
return false;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
}
}
注意消息处理类是无法直接获取请求的,所以如果客户端发来的连接请求带有数据,比如客户端的id之类的,必须在拦截器中处理
(3)注册配置类
@Configuration
@EnableWebSocket
public class TestConfig implements WebSocketConfigurer {
@Autowired
MySocketHandler handler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry arg0) {
arg0.addHandler(handler, "/webForSSM").addInterceptors(new MySocketIntercepter());
System.out.println("已经映射");
}
}
@EnableWebSocket注册到该类上时标识该类是WebSocket的注册类,@Configuration并不是必须的,你用@Componoent也可以,总之能被spring容器扫描即可;
然后是前端的实现:
var websocket;
function on() {
if (typeof(WebSocket) == "undefined") {
alert("此浏览器不支持WebSocket,连接失败;");
} else {
var basePath = [[${basePath}]];
webSocket = new WebSocket((basePath +"webForSSM?id=1").replace('http','ws'));
webSocket.onopen = function() {
$(".res").html($(".res").html() + "已打开");
}
webSocket.onmessage = function (event) {
$(".res").html($(".res").html() + event.data);
}
}
}
function send() {
var value = {message :$(".socketText").val(),
sid : '2'};
webSocket.send(JSON.stringify(value));
}
如果浏览器支持WebSocket,直接new即可,否则也可以使用socketjs,后端注册类时要改动一下:
@Configuration
@EnableWebSocket
public class TestConfig implements WebSocketConfigurer {
@Autowired
MySocketHandler handler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry arg0) {
arg0.addHandler(handler, "/webForSSM").
addInterceptors(new MySocketIntercepter()).withSockJS();
}
}
对了,有关之前的配置消息解析器为什么可以@Bean创建:
@Configuration
public class ConfigurationSet {
@Bean
public StringHttpMessageConverter getConverter() {
StringHttpMessageConverter temp = new StringHttpMessageConverter();
temp.setDefaultCharset(Charset.forName("utf-8"));
return temp;
}
这个是springboot的优点之一,@Bean会自动将注册到容器中的消息转换器放入到消息转换器的list集合中,也就是自动配置; 注意:转换器自动注册机制是由WebMvcAutoConfiguration实现的,如果你的项目继承了WebMvcConfigurationSupport或者它的子类,会失效,只能手动配置
参考的文章:https://charming.blog.csdn.net/article/details/84636521?utm_medium=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-2.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-2.no_search_link
|