" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot集成整合JWT與Shiro流程詳解

 更新時間:2022年12月06日 10:26:11   作者:leo825...  
安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會出現(xiàn)問題,這篇文章主要介紹了SpringBoot集成JWT、Shiro框架的使用

前言

代碼庫:https://gitee.com/leo825/springboot-learning-parents.git

之前寫過《SpringBoot集成Shiro框架》,最近看了JWT,正好兩個整合一下,加深一下理解。

實戰(zhàn)演練

代碼結(jié)構(gòu)

SQL腳本

schema.sql

create table if not exists t_user (
	`id`            int  primary  key not null ,
	`username`      char (50) not null,
	`password`      char(50) not null,
	`role`          char(50) not null,
	`permission`    char(255) not null
) ;

data.sql

insert into t_user(id, username, password, role, permission) values (0,'smith','smith123','user','view');
insert into t_user(id, username, password, role, permission) values (1,'danny','danny123','admin','view,edit')

數(shù)據(jù)格式如下:

usernamepasswordrolepermission
smithsmith123userview
dannydanny123adminview,edit

pom依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.example</groupId>
		<artifactId>springboot-learning-parents</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>
	<groupId>springboot-demo</groupId>
	<artifactId>springboot-jwt-shiro</artifactId>
	<version>1.0-SNAPSHOT</version>
	<name>springboot-jwt-shiro</name>
	<url>https://gitee.com/leo825/springboot-learning-parents.git</url>
	<description>springboot集成jwt和shiro測試</description>
	<properties>
		<start-class>com.demo.SpringbootJwtShiroApplication</start-class>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<mybatisplus.version>3.5.1</mybatisplus.version>
		<freemaker.version>2.3.31</freemaker.version>
		<mysql.version>8.0.28</mysql.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<!-- mybatis-plus 所需依賴  -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>${mybatisplus.version}</version>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-generator</artifactId>
			<version>${mybatisplus.version}</version>
		</dependency>
		<!-- 使用h2內(nèi)存數(shù)據(jù)庫 -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
		</dependency>
		<!-- jwt依賴 -->
		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.8.1</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>
		<!--引入shrio 選擇stater方式-->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring-boot-starter</artifactId>
			<version>1.9.0</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

User

package com.demo.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
 * 用戶
 */
@TableName("t_user")
@Data
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 用戶主鍵
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    /**
     * 用戶名
     */
    private String username;
    /**
     * 密碼
     */
    private String password;
    /**
     * 角色
     */
    private String role;
    /**
     * 權(quán)限
     */
    private String permission;
}

JwtUtil

package com.demo.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
/**
 * jwt工具類
 */
public class JwtUtil {
    /**
     * 過期時間5分鐘
     */
    private static final long EXPIRE_TIME = 5 * 60 * 1000;
    /**
     * jwt 密鑰
     */
    public static final String SECRET = "jwt_secret";
    /**
     * 校驗token是否正確
     *
     * @param token  密鑰
     * @param secret 用戶的密碼
     * @return 是否正確
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }
    /**
     * 獲得token中的信息無需secret解密也能獲得
     *
     * @return token中包含的用戶名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }
    /**
     * 生成簽名,5min后過期
     *
     * @param username 用戶名
     * @param pwd      用戶的密碼
     * @return 加密的token
     */
    public static String sign(String username, String pwd) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(pwd);
            // 附帶username信息
            return JWT.create()
                    .withClaim("username", username)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }
}

UserMapper

package com.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.model.User;
/**
 * 用戶表
 */
public interface UserMapper extends BaseMapper<User> {
}

UserService

public interface UserService extends IService<User> {
    User getUser(String username) throws AuthenticationException;
}

UserServiceImpl

package com.demo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.mapper.UserMapper;
import com.demo.model.User;
import com.demo.service.UserService;
import org.springframework.stereotype.Service;
import javax.security.sasl.AuthenticationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Override
    public User getUser(String username) throws AuthenticationException {
        Map<String,Object> columnMap = new HashMap<>();
        columnMap.put("username", username);
        List<User> users = baseMapper.selectByMap(columnMap);
        if(users.isEmpty()){
            throw new AuthenticationException("User didn't existed!");
        }
        return users.get(0);
    }
}

JwtToken

package com.demo.token;
import org.apache.shiro.authc.AuthenticationToken;
public class JwtToken implements AuthenticationToken {
    // 密鑰
    private String token;
    public JwtToken(String token) {
        this.token = token;
    }
    @Override
    public Object getPrincipal() {
        return token;
    }
    @Override
    public Object getCredentials() {
        return token;
    }
}

MyRealm

package com.demo.realm;
import com.demo.model.User;
import com.demo.service.UserService;
import com.demo.token.JwtToken;
import com.demo.util.JwtUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@Component
@Slf4j
public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    /**
     * 大坑!,必須重寫此方法,不然Shiro會報錯
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }
    /**
     * 只有當(dāng)需要檢測用戶權(quán)限的時候才會調(diào)用此方法,例如checkRole,checkPermission之類的
     *
     * @param principals
     * @return
     */
    @SneakyThrows
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = JwtUtil.getUsername(principals.toString());
        User user = userService.getUser(username);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole(user.getRole());
        Set<String> permission = new HashSet<>(Arrays.asList(user.getPermission().split(",")));
        simpleAuthorizationInfo.addStringPermissions(permission);
        return simpleAuthorizationInfo;
    }
    /**
     * 默認使用此方法認證用戶名正確與否驗證,錯誤拋出異常即可。
     *
     * @param auth
     * @return
     * @throws AuthenticationException
     */
    @SneakyThrows
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) {
        String token = (String) auth.getCredentials();
        // 解密獲得username,用于和數(shù)據(jù)庫進行對比
        String username = JwtUtil.getUsername(token);
        if (username == null) {
            throw new AuthenticationException("token invalid");
        }
        User user = userService.getUser(username);
        if (!JwtUtil.verify(token, username, user.getPassword())) {
            throw new AuthenticationException("Username or password error");
        }
        return new SimpleAuthenticationInfo(token, token, JwtUtil.SECRET);
    }
}

JWTFilter

package com.demo.filter;
import com.demo.token.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * 代碼的執(zhí)行流程 preHandle -> isAccessAllowed -> isLoginAttempt -> executeLogin
 */
@Slf4j
public class JWTFilter extends BasicHttpAuthenticationFilter {
    /**
     * 判斷用戶是否想要登入。
     * 檢測header里面是否包含Authorization字段即可
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest req = (HttpServletRequest) request;
        String authorization = req.getHeader("Authorization");
        return authorization != null;
    }
    /**
     *
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String authorization = httpServletRequest.getHeader("Authorization");
        JwtToken token = new JwtToken(authorization);
        // 提交給realm進行登入,如果錯誤他會拋出異常并被捕獲
        getSubject(request, response).login(token);
        // 如果沒有拋出異常則代表登入成功,返回true
        return true;
    }
    /**
     * 這里我們詳細說明下為什么最終返回的都是true,即允許訪問
     * 例如我們提供一個地址 GET /article
     * 登入用戶和游客看到的內(nèi)容是不同的
     * 如果在這里返回了false,請求會被直接攔截,用戶看不到任何東西
     * 所以我們在這里返回true,Controller中可以通過 subject.isAuthenticated() 來判斷用戶是否登入
     * 如果有些資源只有登入用戶才能訪問,我們只需要在方法上面加上 @RequiresAuthentication 注解即可
     * 但是這樣做有一個缺點,就是不能夠?qū)ET,POST等請求進行分別過濾鑒權(quán)(因為我們重寫了官方的方法),但實際上對應(yīng)用影響不大
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (isLoginAttempt(request, response)) {
            try {
                executeLogin(request, response);
            } catch (Exception e) {
                response401(request, response);
            }
        }
        return true;
    }
    /**
     * 對跨域提供支持
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        // 跨域時會首先發(fā)送一個option請求,這里我們給option請求直接返回正常狀態(tài)
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }
    /**
     * 將非法請求跳轉(zhuǎn)到 /401
     */
    private void response401(ServletRequest req, ServletResponse resp) {
        try {
            HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
            httpServletResponse.sendRedirect("/401");
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }
}

ShiroConfig

package com.demo.config;
import com.demo.filter.JWTFilter;
import com.demo.realm.MyRealm;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
    @Bean("securityManager")
    public DefaultWebSecurityManager getManager(MyRealm realm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        // 使用自己的realm
        manager.setRealm(realm);
        /*
         * 關(guān)閉shiro自帶的session,詳情見文檔
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);
        return manager;
    }
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 添加自己的過濾器并且取名為jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JWTFilter());
        factoryBean.setFilters(filterMap);
        factoryBean.setSecurityManager(securityManager);
        factoryBean.setUnauthorizedUrl("/401");
        /*
         * 自定義url規(guī)則
         * http://shiro.apache.org/web.html#urls-
         */
        Map<String, String> filterRuleMap = new HashMap<>();
        // 所有請求通過我們自己的JWT Filter
        filterRuleMap.put("/**", "jwt");
        // 訪問401和404頁面不通過我們的Filter
        filterRuleMap.put("/401", "anon");
        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }
    /**
     * 下面的代碼是添加注解支持
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 強制使用cglib,防止重復(fù)代理和可能引起代理出錯的問題
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}

TestController

URL作用
/login登入
/article所有人都可以訪問,但是用戶與游客看到的內(nèi)容不同
/require_auth登入的用戶才可以進行訪問
/require_roleadmin的角色用戶才可以登入
/require_permission擁有view和edit權(quán)限的用戶才可以訪問

測試代碼如下:

package com.demo.controller;
import com.demo.common.Result;
import com.demo.model.User;
import com.demo.service.UserService;
import com.demo.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.security.sasl.AuthenticationException;
@Slf4j
@RestController
@RequestMapping("/jwt")
public class TestController {
    @Autowired
    private UserService userService;
    @PostMapping("/login")
    public Result login(@RequestParam("username") String username, @RequestParam("password") String password) throws AuthenticationException {
        User user = userService.getUser(username);
        if (user.getPassword().equals(password)) {
            return new Result(200, "Login success", JwtUtil.sign(username, password));
        } else {
            throw new UnauthorizedException();
        }
    }
    @GetMapping("/article")
    public Result article() {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            return new Result(200, "You are already logged in", null);
        } else {
            return new Result(200, "You are guest", null);
        }
    }
    @GetMapping("/require_auth")
    @RequiresAuthentication
    public Result requireAuth() {
        return new Result(200, "You are authenticated", null);
    }
    @GetMapping("/require_role")
    @RequiresRoles("admin")
    public Result requireRole() {
        return new Result(200, "You are visiting require_role", null);
    }
    @GetMapping("/require_permission")
    @RequiresPermissions(logical = Logical.AND, value = {"view", "edit"})
    public Result requirePermission() {
        return new Result(200, "You are visiting permission require edit,view", null);
    }
    @RequestMapping(path = "/401")
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result unauthorized() {
        return new Result(401, "Unauthorized", null);
    }
}

測試

登錄成功

到此這篇關(guān)于SpringBoot集成整合JWT與Shiro流程詳解的文章就介紹到這了,更多相關(guān)SpringBoot JWT與Shiro內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中多態(tài)的實現(xiàn)原理詳細解析

    Java中多態(tài)的實現(xiàn)原理詳細解析

    這篇文章主要介紹了Java中多態(tài)的實現(xiàn)原理詳細解析,多態(tài)是面向?qū)ο缶幊陶Z言的重要特性,它允許基類的指針或引用指向派生類的對象,而在具體訪問時實現(xiàn)方法的動態(tài)綁定,需要的朋友可以參考下
    2024-01-01
  • JVM系列之:JIT中的Virtual Call接口操作

    JVM系列之:JIT中的Virtual Call接口操作

    這篇文章主要介紹了JVM系列之:JIT中的Virtual Call接口操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 在Windows系統(tǒng)下安裝Thrift的方法與使用講解

    在Windows系統(tǒng)下安裝Thrift的方法與使用講解

    今天小編就為大家分享一篇關(guān)于在Windows系統(tǒng)下安裝Thrift的方法與使用講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Spring 依賴注入的幾種方式詳解

    Spring 依賴注入的幾種方式詳解

    本篇文章主要介紹了Spring 依賴注入的幾種方式詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • 使用Spring框架實現(xiàn)用戶登錄

    使用Spring框架實現(xiàn)用戶登錄

    這篇文章主要為大家詳細介紹了使用Spring框架實現(xiàn)用戶登錄,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • 關(guān)于Java從本地文件復(fù)制到網(wǎng)絡(luò)文件上傳

    關(guān)于Java從本地文件復(fù)制到網(wǎng)絡(luò)文件上傳

    這篇文章主要介紹了關(guān)于Java從本地文件復(fù)制到網(wǎng)絡(luò)文件上傳,File?和?IO?流其實是很相似的,都是將文件從一個地方轉(zhuǎn)移到另一個地方,這也是流的特點之一,需要的朋友可以參考下
    2023-04-04
  • JAVA的發(fā)展前景如何好不好自學(xué)

    JAVA的發(fā)展前景如何好不好自學(xué)

    這篇文章主要介紹了JAVA的發(fā)展前景如何好不好自學(xué),很多朋友想自學(xué)java不知道好不好學(xué),能不能學(xué)會,今天小編給大家分享一篇教程關(guān)于java的發(fā)展前景的文章,需要的朋友可以參考下
    2020-06-06
  • kill命令在Java應(yīng)用中使用的注意事項小結(jié)

    kill命令在Java應(yīng)用中使用的注意事項小結(jié)

    這篇文章主要給大家介紹了關(guān)于kill命令在Java應(yīng)用中使用的注意事項,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 從application.properties配置文件獲取的漢字亂碼的解決方法

    從application.properties配置文件獲取的漢字亂碼的解決方法

    平時從配置文件各種讀取配置參數(shù)都正常,但是有時候放了個中文就亂碼,你肯定試過網(wǎng)上好多方法,都沒解決,那么來看下面,恭喜你終于找這里了,本文給大家介紹了從application.properties配置文件獲取的漢字亂碼的解決方法,需要的朋友可以參考下
    2024-03-03
  • DispatcherServlet處理器的適配和處理解析

    DispatcherServlet處理器的適配和處理解析

    這篇文章主要為大家介紹了DispatcherServlet的處理器的適配和處理流程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06

最新評論