国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring MVC實現Spring Security,Spring Stomp websocket

shuibo / 1609人閱讀

摘要:使用框架各個組件實現一個在線聊天網頁,當有用戶連接,服務器監聽到用戶連接會使用推送最新用戶列表,有用戶斷開刷新在線列表,實時推送用戶聊天信息。根據請求頭是否等于判斷是否是。

使用Spring框架各個組件實現一個在線聊天網頁,當有用戶連接WebSocket,服務器監聽到用戶連接會使用Stomp推送最新用戶列表,有用戶斷開刷新在線列表,實時推送用戶聊天信息。引入Jetty服務器,直接嵌入整個工程可以脫離Java Web容器獨立運行,使用插件打包成一個jar文件,就像Spring Boot一樣運行,部署。

pom.xml 依賴

 
        UTF-8
        UTF-8
        UTF-8
        9.4.8.v20171121
        5.0.4.RELEASE
        2.9.4
        1.16.18
        1.4.196
        1.7.25
        5.0.3.RELEASE
        1.2.3
        5.15.0
    

    
        
            org.eclipse.jetty
            jetty-servlet
            ${jetty.version}
        

        
        
            org.eclipse.jetty.websocket
            websocket-server
            ${jetty.version}
        

        
            org.eclipse.jetty.websocket
            websocket-api
            ${jetty.version}
        

        
        
            org.springframework
            spring-webmvc
            ${spring.version}
        

        
            org.springframework
            spring-jdbc
            ${spring.version}
        

        
            org.springframework
            spring-webflux
            ${spring.version}
        

        
            org.springframework
            spring-websocket
            ${spring.version}
        

        
            org.springframework
            spring-messaging
            ${spring.version}
        

        
        
            org.springframework.security
            spring-security-web
            ${spring.security.version}
        
        
            org.springframework.security
            spring-security-config
            ${spring.security.version}
        

        
            org.springframework.security
            spring-security-oauth2-client
            ${spring.security.version}
        

        
            org.springframework.security
            spring-security-oauth2-jose
            ${spring.security.version}
        


        
            org.springframework.security
            spring-security-messaging
            ${spring.security.version}
        

        
            com.fasterxml.jackson.core
            jackson-core
            ${jackson.version}
        

        
            com.h2database
            h2
            ${dbh2.version}
        

        
            com.fasterxml.jackson.core
            jackson-databind
            ${jackson.version}
        

        
            org.projectlombok
            lombok
            ${lombok.version}
        

        
            org.slf4j
            jcl-over-slf4j
            ${jcl.slf4j.version}
        

        
            ch.qos.logback
            logback-classic
            ${logback.version}
        

        
            org.apache.activemq
            activemq-broker
            ${activemq.version}
        

        
            io.projectreactor.ipc
            reactor-netty
            0.7.2.RELEASE
        

    
1. 配置H2 嵌入式數據庫
    @Bean  //內存模式
    public DataSource  dataSource(){
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase build = builder.setType(EmbeddedDatabaseType.H2)
                .addScript("db/sql/create-db.sql") //每次創建數據源都會執行腳本
                .addScript("db/sql/insert-data.sql")
                .build();
        return build;
    }

這種方式是利用Spring 內置的嵌入式數據庫的數據源模板,創建的數據源,比較簡單,但是這種方式不支持定制,數據只能保存在內存中,項目重啟數據就會丟失了。

設置數據保存到硬盤

    @Bean
    public DataSource dataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName("org.h2.Driver");
            dataSource.setUsername("embedded");
            dataSource.setPassword("embedded");
            dataSource.setUrl("jdbc:h2:file:./data;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;");
            return dataSource;
    }

如果你還想每次創建數據源執行初始化sql,使用org.springframework.jdbc.datasource.init.ResourceDatabasePopulator 裝載sql 腳本用于初始化或清理數據庫

    @Bean
    public ResourceDatabasePopulator databasePopulator() {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(schema);
        populator.addScripts(data);
        populator.setContinueOnError(true);
        return populator;
    }

設置DatabasePopulator 對象,用戶數據源啟動或者消耗的時候執行腳本

 @Bean
    public DataSourceInitializer initializer() {
        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDatabasePopulator(databasePopulator());
        initializer.setDataSource(dataSource());
        return initializer;
    }

啟用H2 web Console

 @Bean(initMethod = "start",destroyMethod = "stop")
    public Server DatasourcesManager() throws SQLException {
        return Server.createWebServer("-web","-webAllowOthers","-webPort","8082");
    }

瀏覽器打開 http://localhost:8082 訪問H2 控制臺

設置事務管理器

 @Bean
    public PlatformTransactionManager transactionManager() {
        PlatformTransactionManager manager = new DataSourceTransactionManager(dataSource());
        return manager;
    }
}

到這里,嵌入H2數據庫配置基本已經設置完成了

2. Spring MVC配置
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "org.ting.spring.controller", //基包路徑設置
        includeFilters = @ComponentScan.Filter(value = 
                {ControllerAdvice.class,Controller.class})) //只掃描MVC controll的注解
public class WebMvcConfiguration implements WebMvcConfigurer {


    public void extendMessageConverters(List> converters) {
        converters.add(new MappingJackson2HttpMessageConverter());
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //添加靜態路徑映射
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}
3. Jetty嵌入式服務

因為Spring 注解掃描只能注冊一個類, 使用@Import引入其他的配置類

@Configuration
@ComponentScan(basePackages = "org.ting.spring",
        excludeFilters = {@ComponentScan.Filter(value = {Controller.class,ControllerAdvice.class})})
@Import({WebMvcConfiguration.class}) //引入Spring MVC配置類
public class WebRootConfiguration {

    @Autowired
    private DataSource dataSource;

    @Bean
    public JdbcTemplate jdbcTemplate(){
        JdbcTemplate template = new JdbcTemplate(dataSource);
        return template;
    }
}

使用Spring AnnotationConfigWebApplicationContext 啟動注解掃描,注冊創建bean將WebApplicationContext,在將對象傳給DispatcherServlet

public class JettyEmbedServer {

    private final static int DEFAULT_PORT = 9999;

    private final static String DEFAULT_CONTEXT_PATH = "/";

    private final static String MAPPING_URL = "/*";

    public static void main(String[] args) throws Exception {
        Server server = new Server(DEFAULT_PORT);
        JettyEmbedServer helloServer = new JettyEmbedServer();
        server.setHandler(helloServer.servletContextHandler());
        server.start();
        server.join();

    }

    private ServletContextHandler servletContextHandler() {
        WebApplicationContext context = webApplicationContext();
        ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
        servletContextHandler.setContextPath(DEFAULT_CONTEXT_PATH);
        ServletHolder servletHolder = new ServletHolder(new DispatcherServlet(context));
        servletHolder.setAsyncSupported(true);
        servletContextHandler.addServlet(servletHolder, MAPPING_URL);
        return servletContextHandler;
    }

    private WebApplicationContext webApplicationContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(WebRootConfiguration.class);
        return context;
    }                  
3. 配置Spring Security

默認Spring Security攔截請求,登錄失敗,登錄成功都是頁面跳轉的方式,我們希望ajax請求的時候,無論是被攔截了,或者登錄失敗,成功都可以返回json格式數據,由前端人員來處理。
根據HttpRequestServlet 請求頭 X-Requested-With是否等于XMLHttpRequest 判斷是否是ajax。

public class RespnonseJson {

    public static void jsonType(HttpServletResponse response) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("utf-8");
    }

    public static boolean ajaxRequest(HttpServletRequest request){
        String header = request.getHeader("X-Requested-With");
        return ! StringUtils.isEmpty(header) && header.equals("XMLHttpRequest");
    }

    public static boolean matchURL(String url) {
        Pattern compile = Pattern.compile("^/api/.+");
        return compile.matcher(url).matches();
    }
}

登錄認證處理器

public class RestAuthenticationEntryPoint  extends LoginUrlAuthenticationEntryPoint {

    /**
     * @param loginFormUrl URL where the login page can be found. Should either be
     *                     relative to the web-app context path (include a leading {@code /}) or an absolute
     *                     URL.
     */
    public RestAuthenticationEntryPoint(String loginFormUrl) {
        super(loginFormUrl);
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        String uri = request.getRequestURI();
        if (matchURL(uri)) {  //  /api 都是ajax 請求
            jsonType(response);
            response.getWriter().println(getErr(authException.getMessage()));
        }else if (ajaxRequest(request)){
            jsonType(response);
            response.getWriter().println(getErr(authException.getMessage()));
        }else super.commence(request,response,authException);
    }

    private String getErr(String description) throws JsonProcessingException {
        Result result = Result.error(Result.HTTP_FORBIDDEN, description);
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(result);
    }
}

登錄成功處理

public class RestAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        String uri = request.getRequestURI();
        if (matchURL(uri)){
            jsonType(response);
            String value = loginSuccess();
            response.getWriter().println(value);
        }else if (ajaxRequest(request)){
            jsonType(response);
            String success = loginSuccess();
            response.getWriter().println(success);
        }else super.onAuthenticationSuccess(request,response,authentication);
    }

    private String loginSuccess() throws JsonProcessingException {
        Result success = Result.success("sign on success go to next!");
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(success);
    }
}

登錄失敗處理

public class RestAuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        if (ajaxRequest(request)){
            jsonType(response);
            String err = getErr(exception.getMessage());
            response.getWriter().println(err);
        }else super.onAuthenticationFailure(request,response,exception);
    }

    public String getErr(String description) throws JsonProcessingException {
        Result result = Result.error(Result.HTTP_AUTH_FAILURE, description);
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(result);
    }
}

我在網上搜索ajax 認證錯誤,很多博客是這樣寫的

response.sendError(500, "Authentication failed");

這個錯誤會被Jetty 錯誤頁面捕獲,擾亂返回JSON數據,這個細節要注意下

注冊Handler

   @Bean
    public AuthenticationEntryPoint entryPoint() {
        RestAuthenticationEntryPoint entryPoint = new RestAuthenticationEntryPoint("/static/html/login.html"); 
        return entryPoint;
    }

    @Bean
    public SimpleUrlAuthenticationSuccessHandler successHandler() {
        RestAuthSuccessHandler successHandler = new RestAuthSuccessHandler();
        return successHandler;
    }

    @Bean
    public SimpleUrlAuthenticationFailureHandler failureHandler() {
        RestAuthFailureHandler failureHandler = new RestAuthFailureHandler();
        return failureHandler;
    }

配置url 認證

    @Bean
    public SessionRegistry sessionManager() {
        return new SessionRegistryImpl();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(entryPoint())
                .and()
                .authorizeRequests()
                .antMatchers("/static/html/jetty-chat.html",
                        "/api/user/online", "/api/user/loginuser") 
                .authenticated() //設置需要認證才可以請求的接口
                .and()
                .formLogin()
                .successHandler(successHandler()) //登錄成功處理
                .failureHandler(failureHandler()) //登錄失敗處理
                .loginPage("/static/html/login.html") //登錄頁面
                .loginProcessingUrl("/auth/login") //登錄表單url 
                .defaultSuccessUrl("/static/html/jetty-chat.html") //成功跳轉url
                .permitAll()
                .and().csrf().disable()//禁用csrf 因為沒有使用模板引擎
                .sessionManagement().maximumSessions(1)  //設置同一個賬戶,同時在線次數
                .sessionRegistry(sessionManager()) // 設置Session 管理器,
                .expiredUrl("/static/html/login.html") //session 失效后,跳轉url
                .maxSessionsPreventsLogin(false) //設置true,達到session 最大登錄次數后,后面的賬戶都會登錄失敗,false 頂號 前面登錄賬戶會被后面頂下線
        ;

      //注銷賬戶,跳轉到登錄頁面
     http.logout().logoutUrl("/logout").logoutSuccessUrl("/static/html/login.html");

在配置類添加@EnableWebSecurity,在掃描類上引入Spring Security配置,大功告成了,并沒有!Spring Security 是使用Filter來處理一些認證請求,需要我們在Jetty中手動注冊攔截器

        //手動注冊攔截器,讓Spring Security 生效
        FilterHolder filterHolder = new FilterHolder(new DelegatingFilterProxy("springSecurityFilterChain"));
        servletContextHandler.addFilter(filterHolder, MAPPING_URL, null);
        servletContextHandler.addEventListener(new ContextLoaderListener(context));
        servletContextHandler.addEventListener(new HttpSessionEventPublisher()); //使用security session 監聽器 限制只允許一個用戶登錄
4. 配置WebSocketStompConfig
@Configuration
@EnableWebSocketMessageBroker
@ComponentScan(basePackages = "org.ting.spring.stomp.message")
@Slf4j
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {

    //設置連接的端點路徑
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("endpoint").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 定義了兩個客戶端訂閱地址的前綴信息,也就是客戶端接收服務端發送消息的前綴信息
        registry.enableSimpleBroker("/topic", "/queue");
        // 定義了服務端接收地址的前綴,也即客戶端給服務端發消息的地址前綴
        registry.setApplicationDestinationPrefixes("/app");
        //使用客戶端一對一通信
        registry.setUserDestinationPrefix("/user");
        registry.setPathMatcher(new AntPathMatcher("."));
    }

}

配置stomp 頻道認證

@Configuration
public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
       messages.simpDestMatchers("/user/**").authenticated()//認證所有user 鏈接
       .anyMessage().permitAll();
    }

    //允許跨域  不然會出現 Could not verify the provided CSRF token because your session was not found 異常
    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}

信息處理

@Controller
@Slf4j
public class StompController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;


    @MessageExceptionHandler
    @SendToUser("/queue.errors")
    public String handleException(Throwable exception) {
        return exception.getMessage();
    }

    @MessageMapping("receive.messgae")
    public void forwardMsg(ChatMessage message){
        log.info("message :  {}",message);
        message.setLocalDateTime(LocalDateTime.now());
        messagingTemplate.convertAndSendToUser(message.getTargetUser().getEmail()
                ,"queue.notification",message);
    }

}

@MessageMapping 作用與@RequestMapping 功能差不多用于匹配url
更多Spring WebSocket 官方文檔查看

我們使用一個集合來保存連接上的用戶,使用連接,斷開監聽器來修改集合的列表,并將集合的數據發布到頻道上。

websocket 斷開連接監聽器

@Component
@Slf4j
public class WebSocketDisconnectListener implements ApplicationListener {

    @Autowired
    private UserService userService;

    @Autowired
    private SimpMessagingTemplate messageTemplate;

    @Override
    public void onApplicationEvent(SessionDisconnectEvent event) {
        Principal principal = event.getUser();
        log.info("client sessionId : {} name : {} disconnect ....",event.getSessionId(),principal.getName());
        if (principal != null){ //已經認證過的用戶
            User user = userService.findByEmail(principal.getName());
            Online.remove(user);
            messageTemplate.convertAndSend("/topic/user.list",Online.onlineUsers());
        }
    }
}

注冊連接websocket 監聽器

@Component
@Slf4j
public class WebSocketSessionConnectEvent implements ApplicationListener{

    @Autowired
    private SimpMessagingTemplate messageTemplate;

    @Autowired
    private UserService userService;

    @Override
    public void onApplicationEvent(SessionConnectEvent event) {
        Principal principal = event.getUser();
        log.info("client name: {} connect.....",principal.getName());
        if (principal != null){
            User user = userService.findByEmail(principal.getName());
            Online.add(user);
            messageTemplate.convertAndSend("/topic/user.list",Online.onlineUsers());
        }
    }
}

保存在線列表

public class Online {

    private static Map maps = new ConcurrentHashMap<>();

    public static void add(User user){
        maps.put(user.getEmail(),user);
    }

    public static void remove(User user){
        maps.remove(user.getEmail());
    }

    public static Collection onlineUsers(){
        return maps.values();
    }

}
4. Spring Security OAuth2 Client 配置

手動配置ClientRegistrationRepository 設置client-id,client-secret,redirect-uri-template

   @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        return new InMemoryClientRegistrationRepository(githubClientRegstrationRepository()
                ,googleClientRegistrionRepository());
    }

    public ClientRegistration githubClientRegstrationRepository(){
        return CommonOAuth2Provider.GITHUB.getBuilder("github")
                .clientId(env.getProperty("registration.github.client-id"))
                .clientSecret(env.getProperty("registration.github.client-secret"))
                .redirectUriTemplate(env.getProperty("registration.github.redirect-uri-template"))
                .build();
    }

    public ClientRegistration googleClientRegistrionRepository(){
         return CommonOAuth2Provider.GOOGLE.getBuilder("google")
                .clientId(env.getProperty("registration.google.client-id"))
                .clientSecret(env.getProperty("registration.google.client-secret"))
                .redirectUriTemplate(env.getProperty("registration.google.redirect-uri-template"))
                .scope( "profile", "email")
                .build();
    }

    @Bean
    public OAuth2AuthorizedClientService authorizedClientService() {
        return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository());
    }

我們使用github,google OAuth2 授權登錄的賬戶,登錄通過后保存起來,則需求繼承DefaultOAuth2UserService

@Service
@Slf4j
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private UserService userService;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest);
        try {
           oAuth2User = processOAuth2User(oAuth2User,userRequest);
        } catch (Exception e) {
            log.error("processOAuth2User error {}",e);
        }
        return oAuth2User;
    }

    private OAuth2User processOAuth2User(OAuth2User oAuth2User,OAuth2UserRequest userRequest) {
        String clientId = userRequest.getClientRegistration().getRegistrationId();
        if (clientId.equalsIgnoreCase("github")) {
            Map map = oAuth2User.getAttributes();
            String login =  map.get("login")+"_oauth_github";
            String name = (String) map.get("name");
            String avatarUrl = (String) map.get("avatar_url");
            User user = userService.findByEmail(login);
            if (user == null) {
                user = new User();
                user.setUsername(name);
                user.setEmail(login);
                user.setAvatar(avatarUrl);
                user.setPassword("123456");
                userService.insert(user);
            }else {
                user.setUsername(name);
                user.setAvatar(avatarUrl);
                userService.update(user);
            }
            return UserPrincipal.create(user, oAuth2User.getAttributes());
        }else if (clientId.equalsIgnoreCase("google")){
            Map result = oAuth2User.getAttributes();
            String email = result.get("email")+"_oauth_google";
            String username = (String) result.get("name");
            String imgUrl = (String) result.get("picture");
            User user = userService.findByEmail(email);
            if (user == null){
                user = new User();
                user.setEmail(email);
                user.setPassword("123456");
                user.setAvatar(imgUrl);
                user.setUsername(username);
                userService.insert(user);
            }else {
                user.setUsername(username);
                user.setAvatar(imgUrl);
                userService.update(user);
            }
            return UserPrincipal.create(user,oAuth2User.getAttributes());
        }
        return null;
    }
}
 

重寫UserDetails

public class UserPrincipal implements OAuth2User,UserDetails {

    private long id;

    private String name;

    private String password;

    private boolean enable;

    private Collection authorities;

    private Map attributes;

    UserPrincipal(long id,String name,String password,boolean enable,Collection authorities){
        this.id = id;
        this.name = name;
        this.password = password;
        this.authorities = authorities;
        this.enable = enable;
    }

    public static UserPrincipal create(User user){
        return new UserPrincipal(user.getId(),user.getEmail()
                ,user.getPassword(),user.isEnable(),Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
    }

    public static UserPrincipal create(User user, Map attributes) {
        UserPrincipal userPrincipal = UserPrincipal.create(user);
        userPrincipal.attributes = attributes;
        return userPrincipal;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return name;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return this.enable;
    }

    @Override
    public Collection getAuthorities() {
        return this.authorities;
    }

    @Override
    public Map getAttributes() {
        return this.attributes;
    }

    @Override
    public String getName() {
        return String.valueOf(this.id);
    }
}

設置Spring Security OAuth2 Client

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomOAuth2UserService customOAuth2UserService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.oauth2Login()
                .clientRegistrationRepository(clientRegistrationRepository())
                .authorizedClientService(authorizedClientService())
                .userInfoEndpoint()
                .userService(customOAuth2UserService)
                .and()
            .defaultSuccessUrl("/static/html/jetty-chat.html");
}
}

默認授權端點,點擊后直接重定向到授權服務器的登錄頁面,Spring 默認是: oauth2/authorization/{clientId}
默認授權成功跳轉url/login/oauth2/code/{clientId}

這個項目參考的教程:
https://www.baeldung.com/spring-security-5-oauth2-login
https://www.callicoder.com/spring-boot-security-oauth2-social-login-part-1/

這個教程只展示了一部分的代碼,想查看完整的項目代碼,可以去github: spring-stomp-security-webflux-embedded-jetty查看

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73414.html

相關文章

  • Spring MVC+Stomp+Security+H2 Jetty

    摘要:在逐步開發過程中,發現自己需求,用戶使用,頁面樣式,做得都不是很好。希望很和牛逼的人合作,一齊完善這個項目,能讓它變成可以使用的產品。自己也可以在此不斷學習,不斷累計新的知識,慢慢變強起來。 showImg(https://segmentfault.com/img/bVboKz5);#### 這一個什么項目 ##### 使用技術 Spring MVC Spring Security ...

    gitmilk 評論0 收藏0
  • spring boot websocket實現

    摘要:子協議只是一個消息傳遞的體系結構,沒有指定任何的消息傳遞協議。是一個簡單的消息傳遞協議,是一種為,面向消息的中間件設計的簡單文本協議。的實現對內嵌的或者和使用了提供了支持。廣播式廣播式即服務端有消息時,會將消息發送到所有連接了當前的瀏覽器。 簡單介紹     WebSocket是為瀏覽器和服務端提供雙工藝部通信功能一種工具,即瀏覽器可以先服務端發送消息,服務端也可以先瀏覽器發送消息。現...

    wuyumin 評論0 收藏0
  • spring boot websocket實現

    摘要:子協議只是一個消息傳遞的體系結構,沒有指定任何的消息傳遞協議。是一個簡單的消息傳遞協議,是一種為,面向消息的中間件設計的簡單文本協議。的實現對內嵌的或者和使用了提供了支持。廣播式廣播式即服務端有消息時,會將消息發送到所有連接了當前的瀏覽器。 簡單介紹     WebSocket是為瀏覽器和服務端提供雙工藝部通信功能一種工具,即瀏覽器可以先服務端發送消息,服務端也可以先瀏覽器發送消息。現...

    lavor 評論0 收藏0
  • websocket配合spring-security使用token認證

    摘要:最后發現每一個在連接端點之前都會發送一個請求用于保證該服務是存在的。而該請求是程序自動發送的自能自動攜帶數據,無法發送自定義。問題是我們的是使用自定義實現的認證。所以該方法不成立,所以只能讓自己認證。 使用框架介紹 spring boot 1.4.3.RELEASE spring websocket 4.3.5.RELEASE spring security 4.1.3.RELEAS...

    CODING 評論0 收藏0
  • Spring新功能

    摘要:新特性重要功能升級為了解決各種環境下如開發測試和生產選擇不同配置的問題,引入了環境功能。這個消息模塊支持的功能,同時提供了基于模板的方式發布消息是第一批支持特性的框架,比如它所支持的表達式。 Spring 3.1新特性 重要功能升級 為了解決各種環境下(如開發、測試和生產)選擇不同配置的問題,Spring 3.1引入了環境profile功能。借助于profile,就能根據應用部署在什...

    baiy 評論0 收藏0

發表評論

0條評論

shuibo

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<