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

Spring AOP如何自定義注解實現(xiàn)審計或日志記錄(完整代碼)

 更新時間:2022年12月28日 14:53:48   作者:DayDayUp丶  
這篇文章主要介紹了Spring AOP如何自定義注解實現(xiàn)審計或日志記錄(完整代碼),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

環(huán)境準(zhǔn)備

JDK 1.8,Springboot 2.1.3.RELEASE,spring-boot-starter-aop.2.1.4.RELEASE.jar,aspectjrt.1.9.2.jar,aspectjweaver.1.9.2.jar,pom依賴如下:

<!-- 添加aspectj -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.2</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.2</version>
</dependency>

項目結(jié)構(gòu)

自定義審計注解

package com.cjia.common.annotation;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD })
public @interface Audit {
 
    /**
     * 模塊代碼
     */
    int moudleCode() default -1;
    
    /**
     * 擴展信息,用戶返回操作類型及參數(shù)
     */
    Class<?> extension();
}

定義切面類

package com.cjia.common.aspect;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import com.cjia.common.Moudle;
import com.cjia.common.Operate;
import com.cjia.common.annotation.Audit;
import com.cjia.common.reflect.BaseValueReturn;
import com.cjia.model.AuditMessage;
import com.cjia.model.ResponseContent;
import com.cjia.model.User;
import com.cjia.service.AuditService;
import com.cjia.service.UserService;
 
@Aspect
@Component
public class AuditAop {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(AuditAop.class);
    @Autowired
    private AuditService auditService;
    @Autowired
    private UserService userService;
    // 操作發(fā)起者
    ThreadLocal<User> user = new ThreadLocal<>();
    // 操作應(yīng)用
    ThreadLocal<Integer> appId = new ThreadLocal<>();
    // 功能模塊
    ThreadLocal<Integer> moudleCode = new ThreadLocal<>();
    // 操作類型
    ThreadLocal<Integer> operateType = new ThreadLocal<>();
    // IP地址
    ThreadLocal<String> ip = new ThreadLocal<>();
    // 操作時間點
    ThreadLocal<String> operateTime = new ThreadLocal<>();
    // 操作信息實體
    ThreadLocal<AuditMessage> msg = new ThreadLocal<>();
    // 對CIS,額外的菜單id信息extension
    ThreadLocal<String> extension = new ThreadLocal<>();
 
    // 聲明AOP切入點
    @Pointcut("@annotation(com.cjia.common.annotation.Audit)")
    public void audit() {
    }
 
    @Before("audit()")
    public void beforeExec(JoinPoint joinPoint) {
    }
 
    @After("audit()")
    public void afterExec(JoinPoint joinPoint) {
    }
 
    @Around("audit()")
    public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            extension.set(request.getParameter("extension"));
            operateTime.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            ip.set(getIpAddr(request));
            appId.set(Integer.valueOf(request.getParameter("appId")));
 
            MethodSignature ms = (MethodSignature) pjp.getSignature();
            Method method = ms.getMethod();
            // 獲取注解的參數(shù)信息
            Audit auditAnno = method.getAnnotation(Audit.class);
            moudleCode.set(auditAnno.moudleCode());
            Class<?> external = auditAnno.extension();
            Constructor<?> cons = external.getConstructor(Integer.class, HttpServletRequest.class);
            BaseValueReturn bvr = (BaseValueReturn) cons.newInstance(moudleCode.get(), request);
            Map<String, Object> reqInfo = bvr.getRequestInfo();
            Integer operate_type = Integer.valueOf(reqInfo.get(BaseValueReturn.OPT) + "");
            operateType.set(operate_type);
            Object target = reqInfo.get(BaseValueReturn.TARGET);
            // 獲取當(dāng)前登錄的用戶,需注意:登錄時沒有msgKey
            String msgKey = request.getParameter("msgKey");
            User loginUser = null;
            if (operate_type.equals(Operate.LOGIN)) {
                List<User> users = userService.selectByEmail(String.valueOf(target));
                if (users != null && !users.isEmpty()) {
                    loginUser = users.get(0);
                }
            } else if (msgKey != null) {
                loginUser = userService.selectMsgFromRedisPurely(msgKey);
            }
            user.set(loginUser);
 
            AuditMessage am = new AuditMessage();
            // am.setUserId需判空,代表過期
            if (loginUser != null) {
                am.setUserId(loginUser.getId());
            } else {
                am.setUserId(-1);
            }
            am.setAppId(appId.get());
            am.setMoudleCode(moudleCode.get());
            am.setOperateType(operateType.get());
            am.setIp(ip.get());
            am.setOperateTime(operateTime.get());
            // TODO details=target
            String details = "";
            if (moudleCode.get() == Moudle.DATA && loginUser != null) {
                details = (String) target;
            } else {
                // TODO 其他模塊
            }
            am.setTarget(details);
            msg.set(am);
            auditService.insert(msg.get());
        } catch (Exception e) {
            LOGGER.error("Error occured while auditing, cause by: ", e);
        } finally {
            // FATAL: remove threadLocal and set threadLocal = null
        }
        Object rtn = pjp.proceed();
        return rtn;
    }
 
    /**
     * 帶參返回
     */
    @AfterReturning(pointcut = "audit()", returning = "rc")
    public void doAfterReturning(ResponseContent rc) {
        LOGGER.debug("afterReturning with returnType..");
    }
 
    /**
     * 不帶參返回
     */
    @AfterReturning(pointcut = "audit()")
    public void doAfterReturning(JoinPoint joinPoint) {
        LOGGER.debug("afterReturning without returnType..");
    }
 
    @AfterThrowing(pointcut = "audit()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        LOGGER.error("Error occured, cause by {}", e.getMessage());
    }
 
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
 
    /** 
     * 獲取用戶真實IP地址,不使用request.getRemoteAddr()的原因是有可能用戶使用了代理軟件方式避免真實IP地址, 
     * 可是,如果通過了多級反向代理的話,X-Forwarded-For的值并不止一個,而是一串IP值 
     *  
     * @return ip
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for"); 
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {  
            // 多次反向代理后會有多個ip值,第一個ip才是真實ip
            if( ip.indexOf(",")!=-1 ){
                ip = ip.split(",")[0];
            }
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("Proxy-Client-IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("WL-Proxy-Client-IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("HTTP_CLIENT_IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("X-Real-IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getRemoteAddr();  
        } 
        return ip;  
    }
 
}

注意事項

第81行的HttpServletRequest request最好設(shè)置為局部變量,或ThreadLocal修飾的成員變量,而非普通成員變量,防止異步請求較多,導(dǎo)致有的request丟失參數(shù)的離奇問題。

定義返回值處理基類

package com.cjia.common.reflect;
 
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
 
public abstract class BaseValueReturn {
    public static final String OPT = "operate";
    public static final String TARGET = "target";
 
    protected Integer moudleCode;
    protected HttpServletRequest request;
 
    public BaseValueReturn(Integer moudleCode, HttpServletRequest request) {
        super();
        this.moudleCode = moudleCode;
        this.request = request;
    }
 
    /**
     * 返回操作動作operate和操作目標(biāo)target
     */
    public abstract Map<String, Object> getRequestInfo();
}

定義返回值處理子類

package com.cjia.common.reflect;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
 
import com.cjia.common.Operate;
 
public class DataValueReturn extends BaseValueReturn {
 
    public DataValueReturn(Integer moudleCode, HttpServletRequest request) {
        super(moudleCode, request);
    }
 
    @Override
    public Map<String, Object> getRequestInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put(OPT, Operate.FETCH_DATA);
        String menuId = request.getParameter("extension");
        info.put(TARGET, menuId);
        return info;
    }
 
}
package com.cjia.common.reflect;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
 
import com.cjia.common.Operate;
 
public class LoginValueReturn extends BaseValueReturn {
 
    public LoginValueReturn(Integer moudleCode, HttpServletRequest request) {
        super(moudleCode, request);
    }
 
    @Override
    public Map<String, Object> getRequestInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put(OPT, Operate.LOGIN);
        String email = request.getParameter("email");
        info.put(TARGET, email);
        return info;
    }
 
}

定義功能模塊類

package com.cjia.common;
 
import java.util.HashMap;
import java.util.Map;
 
public class Moudle {
 
    public static final int LOGIN = 1;
    public static final int DATA = 2;
    public static final int USER = 3;
    // TODO more moudles
    
    private static final Map<Integer, String> moudleMap = new HashMap<>();
    static {
        moudleMap.put(Moudle.LOGIN, "登錄");
        moudleMap.put(Moudle.DATA, "業(yè)務(wù)數(shù)據(jù)");
        moudleMap.put(Moudle.USER, "用戶");
    }
    
    public static String getNameByCode(int code) {
        return moudleMap.get(code);
    }
}

定義操作類

package com.cjia.common;
 
import java.util.HashMap;
import java.util.Map;
 
public class Operate {
 
    public static final int LOGIN = 1;
    // 內(nèi)部系統(tǒng)獲取數(shù)據(jù)
    public static final int FETCH_DATA = 2;
    public static final int INSERT = 3;
    public static final int DELETE = 4;
    public static final int UPDATE = 5;
    public static final int SEARCH = 6;
    // TODO more opts
    
    private static final Map<Integer, String> optMap = new HashMap<>();
    static {
        optMap.put(Operate.LOGIN, "登錄");
        optMap.put(Operate.FETCH_DATA, "獲取業(yè)務(wù)數(shù)據(jù)");
        optMap.put(Operate.INSERT, "新增");
        optMap.put(Operate.DELETE, "刪除");
        optMap.put(Operate.UPDATE, "修改");
        optMap.put(Operate.SEARCH, "查詢");
    }
    
    public static String getNameByCode(int code) {
        return optMap.get(code);
    }
}

定義審計信息實體類

package com.cjia.model;
 
public class AuditMessage {
 
    private int id;
    private int userId;
    private int appId;
    private int moudleCode;
    private int operateType;
    private String ip;
    private String operateTime;
    private String target;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public int getUserId() {
        return userId;
    }
 
    public void setUserId(int userId) {
        this.userId = userId;
    }
 
    public int getAppId() {
        return appId;
    }
 
    public void setAppId(int appId) {
        this.appId = appId;
    }
 
    public int getMoudleCode() {
        return moudleCode;
    }
 
    public void setMoudleCode(int moudleCode) {
        this.moudleCode = moudleCode;
    }
 
    public int getOperateType() {
        return operateType;
    }
 
    public void setOperateType(int operateType) {
        this.operateType = operateType;
    }
 
    public String getIp() {
        return ip;
    }
 
    public void setIp(String ip) {
        this.ip = ip;
    }
 
    public String getOperateTime() {
        return operateTime;
    }
 
    public void setOperateTime(String operateTime) {
        this.operateTime = operateTime;
    }
 
    public String getTarget() {
        return target;
    }
 
    public void setTarget(String target) {
        this.target = target;
    }
 
    @Override
    public String toString() {
        return "AuditMessage [id=" + id + ", userId=" + userId + ", appId=" + appId + ", moudleCode=" + moudleCode
                + ", operateType=" + operateType + ", ip=" + ip + ", operateTime=" + operateTime + ", target=" + target
                + "]";
    }
 
}

書寫mapper文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cjia.dao.AuditMessageMapper">
 
    <resultMap id="BaseResultMap" type="com.cjia.model.AuditMessage">
        <result column="id" jdbcType="INTEGER" property="id" />
        <result column="user_id" jdbcType="VARCHAR" property="userId" />
        <result column="app_id" jdbcType="VARCHAR" property="appId" />
        <result column="moudle_code" jdbcType="VARCHAR" property="moudleCode" />
        <result column="operate_type" jdbcType="INTEGER" property="operateType" />
        <result column="ip" jdbcType="VARCHAR" property="ip" />
        <result column="operate_time" jdbcType="INTEGER" property="operateTime" />
        <result column="target" jdbcType="VARCHAR" property="target" />
    </resultMap>
 
    <!-- 對應(yīng)的插入字段的名字 -->
    <sql id="keys">
        <trim suffixOverrides=",">
            <if test="id!=null and id!=''">
                id,
            </if>
            <if test="userId!=null and userId!=''">
                user_id,
            </if>
            <if test="appId!=null and appId!=''">
                app_id,
            </if>
            <if test="moudleCode!=null and moudleCode!=''">
                moudle_code,
            </if>
            <if test="operateType!=null and operateType!=''">
                operate_type,
            </if>
            <if test="ip!=null and ip!=''">
                ip,
            </if>
            <if test="operateTime!=null and operateTime!=''">
                operate_time,
            </if>
            <if test="target!=null and target!=''">
                target,
            </if>
        </trim>
    </sql>
 
    <!-- 對應(yīng)的插入字段的值 -->
    <sql id="values">
        <trim suffixOverrides=",">
            <if test="id!=null and id!=''">
                #{id},
            </if>
            <if test="userId!=null and userId!=''">
                #{userId},
            </if>
            <if test="appId!=null and appId!=''">
                #{appId},
            </if>
            <if test="moudleCode!=null and moudleCode!=''">
                #{moudleCode},
            </if>
            <if test="operateType!=null and operateType!=''">
                #{operateType},
            </if>
            <if test="ip!=null and ip!=''">
                #{ip},
            </if>
            <if test="operateTime!=null and operateTime!=''">
                #{operateTime},
            </if>
            <if test="target!=null and target!=''">
                #{target},
            </if>
        </trim>
    </sql>
    <insert id="insert" parameterType="com.cjia.model.AuditMessage">
        insert into audit_message(
        <include refid="keys" />
        )
        values(
        <include refid="values" />
        )
    </insert>
 
    <select id="selectAll" resultMap="BaseResultMap">
        select * from audit_message
    </select>
 
</mapper>

開啟AOP攔截

package com.cjia;
 
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
 
@SpringBootApplication
@MapperScan("com.cjia.dao")
@EnableAspectJAutoProxy(exposeProxy=true)
public class DataserviceApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(DataserviceApplication.class, args);
    }
 
}

或在配置文件中:

<!-- 開啟AOP攔截 -->
<aop:aspectj-autoproxy proxy-target-class="true" /> 
<mvc:annotation-driven />
<!-- 定義Spring描述Bean的范圍,使切面類AuditAop可以被掃描到  -->
<context:component-scan base-package="**.common" >
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

注解配置

package com.cjia.controller;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
 
import javax.servlet.http.HttpServletRequest;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import com.alibaba.fastjson.JSON;
import com.cjia.common.InnerApp;
import com.cjia.common.Moudle;
import com.cjia.common.ResConstance.UserGroup;
import com.cjia.common.annotation.Audit;
import com.cjia.common.reflect.LoginValueReturn;
import com.cjia.model.Menu;
import com.cjia.model.ResponseContent;
import com.cjia.model.User;
import com.cjia.service.MenuService;
import com.cjia.service.UserService;
import com.cjia.utils.DigestUtil;
 
/**
 * 處理內(nèi)部系統(tǒng)登錄信息驗證
 */
@Controller
public class LoginController {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
 
    @Autowired
    private UserService userService;
 
    @Autowired
    private MenuService menuService;
 
    /**
     * 處理登錄頁表單提交信息
     */
    @ResponseBody
    @PostMapping("/doLogin")
    @Audit(moudleCode = Moudle.LOGIN, extension = LoginValueReturn.class)
    public ResponseContent doLogin(HttpServletRequest req) throws Exception {
        String email = req.getParameter("email");
        String password = req.getParameter("password");
        int appId = Integer.valueOf(req.getParameter("appId"));
        // 獲取到的這么多user(同一賬戶)只是role或門店不同,密碼等其他都一致
        List<User> users = new ArrayList<>();
        // 對SRP報表系統(tǒng)不允許管家登錄
        if (appId == InnerApp.CIS) {
            users = userService.selectByEmail4CIS(email);
        } else {
            users = userService.selectByEmail(email);
        }
        ResponseContent responseContent = new ResponseContent();
        if (users != null && !users.isEmpty()
                && users.get(0).getPassword().equals(DigestUtil.threeHash(password, users.get(0).getSecurityKey()))) {
            User user = users.get(0);
            LOGGER.debug("登陸驗證成功{}", user);
            // 設(shè)置roleIdLst和branchMap
            List<Integer> roleIdLst = users.stream().map(User::getRoleId).collect(Collectors.toList());
            Map<String, String> branchMap = new HashMap<>();
            Map<Integer, List<Menu>> menuMap = getAllMenus(users);
            for (User u : users) {
                branchMap.put(u.getBranchId() + "", u.getBranchName());
            }
            user.setRoleIdLst(roleIdLst);
            user.setBranchMap(branchMap);
            // 給user設(shè)置菜單列表
            user.setMenuMap(menuMap);
            // 登陸成功后,需要看此用戶的信息是否存在于redis,存在則刷新過期時間,不存在則插入記錄
            String msgKey = userService.insertIntoRedis(user);
            responseContent.setRespCode(ResponseContent.RESPCODE_SUCCESS);
            responseContent.setMessage("登陸成功");
            responseContent.setData(msgKey);
        } else {
            LOGGER.debug("登陸驗證失敗");
            responseContent.setRespCode(ResponseContent.RESPCODE_FAILURE);
            responseContent.setMessage("登陸失敗,請檢查用戶賬號密碼是否正確");
        }
        String jsonString = JSON.toJSONString(responseContent);
        LOGGER.debug("登錄返回信息:{}", jsonString);
        return responseContent;
    }
}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Java二叉排序樹

    詳解Java二叉排序樹

    這篇文章主要介紹了Java二叉排序樹,包括二叉排序樹的定義、二叉排序樹的性質(zhì)、二叉排序樹的插入和查找等,感興趣的小伙伴們可以參考一下
    2015-12-12
  • java編程題之順時針打印矩陣

    java編程題之順時針打印矩陣

    這篇文章主要為大家詳細介紹了java編程題之順時針打印矩陣,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Java查看和修改線程優(yōu)先級操作詳解

    Java查看和修改線程優(yōu)先級操作詳解

    JAVA中每個線程都有優(yōu)化級屬性,默認(rèn)情況下,新建的線程和創(chuàng)建該線程的線程優(yōu)先級是一樣的。本文將為大家詳解Java查看和修改線程優(yōu)先級操作的方法,需要的可以參考一下
    2022-08-08
  • 淺談java中OO的概念和設(shè)計原則(必看)

    淺談java中OO的概念和設(shè)計原則(必看)

    下面小編就為大家?guī)硪黄獪\談java中OO的概念和設(shè)計原則(必看)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Java實戰(zhàn)之小米交易商城系統(tǒng)的實現(xiàn)

    Java實戰(zhàn)之小米交易商城系統(tǒng)的實現(xiàn)

    這篇文章將利用Java實現(xiàn)小米交易商城系統(tǒng),文中采用的技術(shù)有:JSP?、Spring、SpringMVC、MyBatis等,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-04-04
  • javaweb用戶注銷后點擊瀏覽器返回刷新頁面重復(fù)登錄問題的解決方法

    javaweb用戶注銷后點擊瀏覽器返回刷新頁面重復(fù)登錄問題的解決方法

    這篇文章主要為大家詳細介紹了javaweb用戶注銷后點擊瀏覽器返回刷新頁面重復(fù)登錄問題的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 詳解Java8函數(shù)式編程之收集器的應(yīng)用

    詳解Java8函數(shù)式編程之收集器的應(yīng)用

    這篇文章主要介紹了詳解Java8函數(shù)式編程之收集器的應(yīng)用,收集器是一種通用的、從流生成復(fù)雜值的結(jié)構(gòu)。可以使用它從流中生成List、Set、Map等集合,需要的朋友可以參考下
    2023-04-04
  • SpringBoot實現(xiàn)JWT token自動續(xù)期的示例代碼

    SpringBoot實現(xiàn)JWT token自動續(xù)期的示例代碼

    本文主要介紹了SpringBoot實現(xiàn)JWT token自動續(xù)期的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Spring注解之@PropertySource詳解

    Spring注解之@PropertySource詳解

    這篇文章主要介紹了Spring注解之@PropertySource詳解,@PropertySource注解用于指定資源文件讀取的位置,它不僅能讀取properties文件,也能讀取xml文件,并且通過YAML解析器,配合自定義PropertySourceFactory實現(xiàn)解析YAML文件,需要的朋友可以參考下
    2023-11-11
  • Java中的方法、常量、變量、參數(shù)用例詳解

    Java中的方法、常量、變量、參數(shù)用例詳解

    在JVM的運轉(zhuǎn)中,承載的是數(shù)據(jù),而數(shù)據(jù)的一種變現(xiàn)形式就是“量”,量分為:常量與變量,我們在數(shù)學(xué)和物理學(xué)中已經(jīng)接觸過變量的概念了,在Java中的變量就是在程序運行過程中可以改變其值的量,這篇文章主要介紹了Java中的方法、常量、變量、參數(shù),需要的朋友可以參考下
    2024-01-01

最新評論