主頁 > 後端開發 > SpringMvc(五) - 支付寶沙箱和關鍵字過濾,md5加密,SSM專案重要知識點

SpringMvc(五) - 支付寶沙箱和關鍵字過濾,md5加密,SSM專案重要知識點

2022-10-10 06:26:43 後端開發

1、支付寶沙箱

1.1 jar包 alipay-sdk

<!-- alipay-sdk -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.10.90.ALL</version>
</dependency>

1.2 資訊配置類

1.2.1 配置資訊

public class AlipayConfig {
	// 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號
	public static String app_id = "";

	// 商戶應用私鑰,您的PKCS8格式RSA2私鑰
	public static String merchant_private_key = "";
	// 對應APPID下的支付寶公鑰,
	public static String alipay_public_key = "";
    
	// 服務器異步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
	public static String notify_url = "http://localhost:8080(/專案名,沒有的不需要)/Alipay/notify_url.do";

	// 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
	public static String return_url = "http://localhost:8080(/專案名,沒有的不需要)/Alipay/alipay_return.do";

	// 簽名方式
	public static String sign_type = "RSA2";

	// 字符編碼格式
	public static String charset = "UTF-8";

	// 支付寶網關
	public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
}

1.2.2配置資訊來源

登錄自己已經入駐的支付寶賬號:https://open.alipay.com/develop/sandbox/app

1.2.2.1 APPID

1.2.2.2 公鑰,私鑰

1.3 支付控制層

/**
 * 支付寶支付
 */
@Controller
@RequestMapping("/Alipay")
public class AlipayController {

    /**
     * 生成訂單直接跳轉支付寶付款
     */
    @RequestMapping("/to_alipay.do")
    public void toAlipay(HttpServletResponse response, HttpServletRequest request) throws Exception{

        AlipayClient alipayClient = new DefaultAlipayClient(
                AlipayConfig.gatewayUrl, AlipayConfig.app_id,
                AlipayConfig.merchant_private_key, "json", AlipayConfig.charset,
                AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        // 取購買人名稱
        String in_name = request.getParameter("in_name");
        // 取手機號
        String in_phone = request.getParameter("in_phone");
        // 創建唯一訂單號
        int random = (int) (Math.random() * 10000);
        String dateStr = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());

        // 訂單號拼接規則:手機號后四位+當前時間后四位+亂數四位數
        String out_trade_no = in_phone.substring(7) + dateStr.substring(10)
                + random;
        // 拼接訂單名稱
        String subject = in_name + "的訂單";

        // 取付款金額
        String total_amount = request.getParameter("in_money");

        // 設定請求引數
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);//支付成功回應后跳轉地址
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);//異步請求地址

        /*FAST_INSTANT_TRADE_PAY 二維碼瞬時支付
         * out_trade_no 訂單號 total_amount 訂單金額  subject 訂單名稱
         */
        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no
                + "\"," + "\"total_amount\":\"" + total_amount + "\","
                + "\"subject\":\"" + subject + "\"," + "\"body\":\""
                + ""+ "\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        String result = "請求無回應";
        // 請求
        try {
            //通過阿里客戶端,發送支付頁面請求
            result = alipayClient.pageExecute(alipayRequest).getBody();
            response.setContentType("text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println(result);
            response.getWriter().flush();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        } finally {
            response.getWriter().close();
        }
    }


    /**
     * 支付成功后處理業務
     */
    @RequestMapping("/alipay_return.do")
    public String alipayReturn(HttpServletRequest request, Map<String, Object> map) throws Exception{

        // 回應資訊
        String msg = "";

        // 請在這里撰寫您的程式(以下代碼僅作參考)
        if (verifyAlipayReturn(request)) {//驗簽成功后執行的自定義業務代碼
            // 商戶訂單號
            String out_trade_no = new String(request.getParameter(
                    "out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

            // 支付寶交易號
            String trade_no = new String(request.getParameter("trade_no")
                    .getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

            // 付款金額
            String total_amount = new String(request.getParameter(
                    "total_amount").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            msg = "支付寶交易號:" + trade_no + "<br/>商戶訂單號"
                    + out_trade_no + "<br/>付款金額:" + total_amount;

        } else {
            msg = "驗簽/支付失敗";
        }

        map.put("msg", msg);

        return "forward:/success.jsp"; //支付完成后,跳轉的頁面
    }

    /**
     * 支付寶異步通知
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/notify_url.do")
    public void alipayNotify(HttpServletRequest request,HttpServletResponse response)
                                                throws Exception {
        // ——請在這里撰寫您的程式(以下代碼僅作參考)——

        /*
         * 實際驗證程序建議商戶務必添加以下校驗: 1、需要驗證該通知資料中的out_trade_no是否為商戶系統中創建的訂單號,
         * 2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單創建時的金額),
         * 3、校驗通知中的seller_id(或者seller_email)
         * 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)
         * 4、驗證app_id是否為該商戶本身,
         */
        if (verifyAlipayReturn(request)) {// 驗證成功
            // 商戶訂單號
            String out_trade_no = new String(request.getParameter(
                    "out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            System.out.println(out_trade_no);
            // 支付寶交易號
            String trade_no = new String(request.getParameter("trade_no")
                    .getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            System.out.println(trade_no);

            // 交易狀態
            String trade_status = new String(request.getParameter(
                    "trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

            if (trade_status.equals("TRADE_FINISHED")) {
                // 判斷該筆訂單是否在商戶網站中已經做過處理
                // 如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,并執行商戶的業務程式
                // 如果有做過處理,不執行商戶的業務程式
                // 注意:
                // 退款日期超過可退款期限后(如三個月可退款),支付寶系統發送該交易狀態通知
            } else if (trade_status.equals("TRADE_SUCCESS")) {
                // 判斷該筆訂單是否在商戶網站中已經做過處理
                // 如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,并執行商戶的業務程式
                // 如果有做過處理,不執行商戶的業務程式
                // 注意:
                // 付款完成后,支付寶系統發送該交易狀態通知
            }

        } else {// 驗證失敗
            response.setContentType("text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println("驗簽/支付失敗!");
            response.getWriter().flush();
            response.getWriter().close();

            // 除錯用,寫文本函式記錄程式運行情況是否正常
            // String sWord = AlipaySignature.getSignCheckContentV1(params);
            // AlipayConfig.logResult(sWord);
        }
    }

    /**
     * @author zhukang
     * @date 2021-04-23
     * @return
     * @description 驗證支付寶的反饋資訊
     */
    private boolean verifyAlipayReturn(HttpServletRequest request) throws UnsupportedEncodingException {
        // 獲取支付寶回呼反饋的資訊
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter
                .hasNext();) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            // 亂碼解決,這段代碼在出現亂碼時使用
            valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            params.put(name, valueStr);
        }

        boolean signVerified = false;
        try {// 呼叫SDK驗證簽名
            signVerified = AlipaySignature.rsaCheckV1(params,
                    AlipayConfig.alipay_public_key, AlipayConfig.charset,
                    AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return signVerified;
    }

}

1.4 測驗訪問

直接訪問 Alipay/to_alipay.do 這個請求即可(引數根據實際操作進行添加);

2、關鍵字過濾

2.1 關鍵字檔案 sensitivewords.txt

小笨蛋
...(根據實際需求添加關鍵字)

2.2 關鍵字工具類

2.2.1 關鍵字初始化


/**
 * Created On : 2022/7/26.
 * <p>
 * Author : zhukang
 * <p>
 * Description: 敏感詞初始化類
 */
public class SensitiveWordInit {
    // 敏感詞集合
    public static Map sensitiveWordMap;

    // 初始化敏感詞
    public Map initSensitiveWord(){
        System.out.println("------- 系統啟動,從檔案中讀取敏感字,存入sensitiveWordMap -------");

        try {
            // 讀取敏感詞檔案,將敏感詞加入HashMap
            addSensitiveWordToHashMap(readSensitiveWordFile());

        } catch (Exception e){
            e.printStackTrace();
        }
        return sensitiveWordMap;
    }

    /**
     * @author : zhukang
     * @date   : 2022/7/26
     * @param  : [java.util.Set<java.lang.String>]
     * @return : java.util.Map
     * @description : 將HashSet中的敏感詞,存入HashMap中
     */
    private void addSensitiveWordToHashMap(Set<String> wordSet) {
        // 初始化敏感詞容器,減少擴容操作
        sensitiveWordMap = new HashMap(wordSet.size());
        for (String word : wordSet) {
            Map nowMap = sensitiveWordMap;
            for (int i = 0; i < word.length(); i++) {
                // 轉換成char型
                char keyChar = word.charAt(i);
                // 獲取
                Object tempMap = nowMap.get(keyChar);
                // 如果存在該key,直接賦值
                if (tempMap != null) {
                    // 一個一個放進Map中
                    nowMap = (Map) tempMap;
                }
                // 不存在則,則構建一個map,同時將isEnd設定為0,因為他不是最后一個
                else {
                    // 設定標志位,不是最后一個
                    Map<String, String> newMap = new HashMap<String, String>();
                    // 沒有這個key,就把(isEnd,0) 放在Map中
                    newMap.put("isEnd", "0");
                    // 添加到集合
                    nowMap.put(keyChar, newMap);
                    //指向當前map,繼續遍歷
                    nowMap = newMap;
                }
                // 最后一個
                if (i == word.length() - 1) {
                    nowMap.put("isEnd", "1");
                }
            }
        }
    }

    /**
     * @author : zhukang
     * @date   : 2022/7/26
     * @param  : []
     * @return : java.util.Set<java.lang.String>
     * @description : 讀取敏感詞庫檔案,存入HashMap中
     */
    private Set<String> readSensitiveWordFile() {
        // 敏感詞集合
        Set<String> wordSet = null;
        //敏感詞庫
        try
                (
                // 獲取輸入流,讀取resources目錄下的static目錄中的敏感詞檔案(一個敏感詞一行)
                InputStream inputStream = new ClassPathResource("sensitivewords.txt").getInputStream();

                // 讀取檔案輸入流
                InputStreamReader read = new InputStreamReader(inputStream, "UTF-8");

                // 高效讀取
                BufferedReader br = new BufferedReader(read);
        )
        {
            // 創建set集合,存盤讀取的敏感字
            wordSet = new HashSet<>();


            //手動 添加詞語
//            wordSet.add("笨蛋");
//            wordSet.add("傻瓜");

            // 讀取檔案,將檔案內容放入到set中
            String txt = null;
            while ((txt = br.readLine()) != null) {
                wordSet.add(txt);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 回傳敏感字集合
        return wordSet;
    }
}

2.2.2 關鍵字過濾類

/**
 * Created On : 2022/7/26.
 * <p>
 * Author : zhukang
 * <p>
 * Description: 敏感字過濾工具類
 */
@Component
public class SensitiveWordFilterUtil {
    // 最小匹配規則
    public static final int MIN_MATCH_TYPE = 1;

    // 最大匹配規則
    public static final int MAX_MATCH_TYPE = 2;

    // 敏感詞集合
    public static Map sensitiveWordMap;

    // 應用啟動后,創建實體物件,自動執行此方法
    @PostConstruct
    public void init() {
        // 從資料庫查詢敏感詞,轉換為set集合 將敏感詞庫加入到HashMap中,確定有窮自動機DFA
        sensitiveWordMap = new com.kgc.weddingshop.utils.SensitiveWordInit().initSensitiveWord();

        System.out.println("------ " + sensitiveWordMap + "------");
    }

    /**
     * @param : [java.lang.String]
     * @return : boolean true 包含;false 不包含
     * @author : zhukang
     * @date : 2022/7/26
     * @description : 是否包含敏感詞(默認按最小匹配規則來,只要有敏感詞就ok),最小匹配規則
     */
    public boolean isContainSensitiveWordMin(String txt) {
        return isContainSensitiveWord(txt, MIN_MATCH_TYPE);
    }

    /**
     * @param : [java.lang.String, int]
     * @return : boolean
     * @author : zhukang
     * @date : 2022/7/26
     * @description : 是否包含敏感詞(默認按指定匹配規則來,只要有敏感詞就ok)
     * 如果敏感詞庫為:
     * * 傻叉
     * * 傻叉人
     * * 大傻叉
     * * 初始化之后為:{傻={叉={人={isEnd=1}, isEnd=1}, isEnd=0}, 大={傻={叉={isEnd=1}, isEnd=0}, isEnd=0}}
     * * 1、按最小規則匹配,  匹配 傻叉 的時候,匹配到叉,就為最后一個了 直接break,如果輸入的敏感詞是傻叉人,命中的只是傻叉,而不是傻叉人
     * * 2、按最大規則匹配,  匹配 傻叉 的時候,匹配到叉,已經為最后一個,但是按照最大規則,會繼續匹配人,命中的是傻叉人
     * * 3、如果關鍵詞是傻叉貓,兩種匹配規則都會匹配到傻叉,會命中,如果輸入的是傻叉人貓,按最小規則匹配是傻叉,按最大規則匹配傻叉人,只是匹配敏感詞不同
     */
    public boolean isContainSensitiveWord(String txt, int matchType) {
        if (txt == null || "".equals(txt)) {
            return false;
        }
        for (int i = 0; i < txt.length(); i++) {
            int matchFlag = this.checkSensitiveWords(txt, i, matchType);
            if (matchFlag > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param : 待判斷文本 起始位置 匹配型別: 1 最小匹配原則;2 最大匹配原則
     * @return : int 大于0表示包含敏感詞且表示敏感詞匹配長度,否則不包含
     * @author : zhukang
     * @date : 2022/7/26
     * @description : 校驗是否包含敏感詞
     */
    private static int checkSensitiveWords(String txt, int beginIndex, int matchType) {
        // 敏感詞結束標識位:用于敏感詞只有1位的情況
        boolean flag = false;

        // 匹配標識數默認為0
        int matchFlag = 0;
        // 從記憶體中,獲取敏感詞庫
        Map nowMap = sensitiveWordMap;
        for (int i = beginIndex; i < txt.length(); i++) {
            // 獲取第一個字符
            char word = txt.charAt(i);

            // 獲取指定key,判斷當前字符是不是一個敏感詞的開頭
            nowMap = (Map) nowMap.get(word);

            // 不存在,直接回傳
            if (nowMap == null) {
                break;
            }

            // 根據排列組合的匹配,如果出現在敏感詞庫中,即找到相應key,匹配標識+1
            matchFlag++;

            // 如果已經匹配到詞庫中完整的敏感詞, 改匹配結束標識,并根據匹配規則判斷,是否繼續
            if ("1".equals(nowMap.get("isEnd"))) {
                // 結束標志位為true,已經命中到了一個完整敏感詞
                flag = true;

                // 最小規則,直接回傳, 最大規則還需繼續查找
                if (matchType == MIN_MATCH_TYPE) {
                    break;
                }
            }
        }

        // 長度必須大于等于1,為詞,敏感詞只有1個字的情況
        if (matchFlag < 2 || !flag) {
            matchFlag = 0;
        }

        return matchFlag;
    }


    /**
     * @param : txt 待判斷文本
     * @return : 匹配型別: 1 最小匹配原則;2 最大匹配原則
     * @author : zhukang
     * @date : 2022/7/26
     * @description :  獲取匹配的敏感詞
     */
    public Set<String> getSensitiveWords(String txt, Integer matchType) {
        Set<String> sensitiveWords = new HashSet<>();

        for (int i = 0; i < txt.length(); i++) {
            Integer length = checkSensitiveWords(txt, i, matchType);
            if (length > 0) {
                sensitiveWords.add(txt.substring(i, i + length));
                // 回圈i會+1,所以需-1
                i = i + length - 1;
            }
        }
        return sensitiveWords;
    }

    /**
     * @param : txt,文本 matchType 匹配型別: 1 最小匹配原則;2 最大匹配原則
     * @return : 替換字符
     * @author : zhukang
     * @date : 2022/7/26
     * @description :  替換敏感詞
     */
    public String replaceSensitiveWords(String txt, Integer matchType, String replaceStr) {
        if (txt == null || "".equals(txt)) {
            return txt;
        }
        // 獲取所有敏感詞
        Set<String> sensitiveWords = getSensitiveWords(txt, matchType);
        Iterator<String> iterator = sensitiveWords.iterator();
        String replaceString = "";
        while (iterator.hasNext()) {
            String sWord = iterator.next();
            replaceString = getReplaceString(replaceStr, sWord.length());
            txt = txt.replaceAll(sWord, replaceString);
        }
        return txt;
    }

    /**
     * @param : replaceStr 替換字符
     * @return : 敏感字長度
     * @author : zhukang
     * @date : 2022/7/26
     * @description :  替換為指定字符,沒有指定替換字符,默認*
     */
    private static String getReplaceString(String replaceStr, Integer length) {
        // 指定替換字符為*
        if (replaceStr == null) {
            replaceStr = "*";
        }
        // 可變字串物件
        StringBuffer replaceString = new StringBuffer();
        // 回圈遍歷,替換內容
        for (int i = 0; i < length; i++) {
            replaceString.append(replaceStr);
        }
        return replaceString.toString();
    }

}

2.3 關鍵字過濾 控制層

/**
 * Created On : 2022/7/26.
 * <p>
 * Author : zhukang
 * <p>
 * Description: 敏感詞測驗入口
 */
@Controller
public class SensitiveWordController {

    @Autowired
    private SensitiveWordFilterUtil sensitiveWordFilterUtil;

    /**
     * @author : zhukang
     * @date   : 2022/5/17
     * @param  : [java.lang.String]
     * @return : com.kgc.sbt.util.RequestResult<java.lang.String>
     * @description : 測驗搜索中的敏感詞,并指定規則
     */
    @RequestMapping(value = "https://www.cnblogs.com/testSensitiveWord", produces = {"application/json;charset=utf-8"})
    @ResponseBody
    public String testSensitiveWord(@RequestParam String searchKey, @RequestParam int matchType){

        // 校驗搜索關鍵字中,是否包含敏感詞,如果包含,提示錯誤
        if(sensitiveWordFilterUtil.isContainSensitiveWord(searchKey, matchType)){
            System.out.println(String.format("------ 命中敏感詞,搜索關鍵字:%s ------", searchKey));
            System.out.println(String.format("------ 命中敏感字為:%s ------", sensitiveWordFilterUtil.getSensitiveWords(searchKey, matchType)));
            return "搜索失敗,命中敏感詞!";
        }
        return "搜索成功!";
    }

}

3、SSM專案 知識點

3.1 SpringMvc 重定向后,中文亂碼

3.1.1 RedirectAttributes attributes

將引數,放入RedirectAttributes 中,在重定向的時候,會自動拼接引數,并且不會亂碼;

@RequestMapping("/test")
public String delAllViewHistory(//attributes 請求,自動拼接引數
    RedirectAttributes attributes){
    
    attributes.addAttribute("test","測驗");
    return "redirect:/viewHistory/viewViewHistoryList";

}

3.2 location.href 會暴露引數問題

解決方法:創建一個form表單,進行post方法提交;

//創建一個 form 表單,并提交
var form = $("<form>");
    
form.attr("style","display:none");
form.attr("target","");
form.attr("method","post");
    
//請求地址
form.attr("action","${pageContext.request.contextPath}/user/modUserInfo");

//請求引數
var input1 = $("<input>");
var input2 = $("<input>");
input1.attr("type","hidden");
input1.attr("name","uid");
input1.attr("value","${sessionScope.loginUser.uid}");
input2.attr("type","hidden");
input2.attr("name","password");
input2.attr("value",$password.val());

//在body標簽中追加form 表單
$("body").append(form);
form.append(input1);
form.append(input2);

//表單體提交
form.submit();

//移除表達
form.remove();

3.3 mysql 查詢日期操作 ,今天,本周,本月,本季度,今年

-- 今天
select to_days(now()) -- 738788 天

-- 本周
select yearweek(now(),1) -- 202239 周, 第二個引數,是因為,中國人喜歡將周一當作一周的第一天

-- 本月
select date_format(now(),'%Y%m') --  202209 月 

-- 本季度
select quarter(now()) -- 3 季度 quarter

-- 今年
select year(now()) -- 2022 年 year

-- 日期格式化
select DATE_FORMAT(now(),'%Y-%m-%d')

3.4 頭像點擊上傳

3.4.1 jsp

3.4.1.1 頭像修改表單
<%--     頭像修改 form    start   --%>
<form action="${pageContext.request.contextPath}/user/headImg" method="post" enctype="multipart/form-data"  id="userHeadImgForm">
    <input type="file" name="userHeaderImg" id="userHeaderPic" style="display: none"/>
</form>
<%--     頭像修改 form    end   --%>
3.4.1.2 頭像展示
<%--     頭像 展示  start   --%>
<h3>
    <a style="margin-left: 130px">
        <img style=" width: 50px;height: 50px"
             id="userHeaderImg"
             src="https://www.cnblogs.com/xiaoqigui/archive/2022/10/09/${pageContext.request.contextPath}/${sessionScope.loginUser.uhead}"/>
    </a>
</h3>
<%--     頭像 展示  end   --%>
3.4.1.3 點擊頭像觸發 圖片選擇input 頭像選擇
//============  頭像更換 start ================
$(function (){

    // 點擊頭像圖片,觸發檔案預點擊
    $("#userHeaderImg").click(function (){
        $("#userHeaderPic").click();
    });

    // 當檔案域內容改變,實作頭像預覽
    $("#userHeaderPic").change(function () {

        // 獲取上傳檔案物件
        var file = $(this)[0].files[0];

        // 判斷型別
        var imageType = /^image\//;
        if (file === undefined || !imageType.test(file.type)) {
            alert("請選擇圖片!");
            return;
        }
        // 判斷大小
        if (file.size > 512000) {
            alert("圖片大小不能超過500K!");
            return;
        }

        // 讀取檔案URL,預覽檔案
        var reader = new FileReader();
        // 讀取檔案
        reader.readAsDataURL(file);
        // 閱讀檔案完成后觸發的事件
        reader.onload = function () {
            // 讀取的URL結果:this.result
            $("#userHeaderImg").attr("src", this.result);
            // alert("圖片上傳");
            $("#userHeadImgForm").submit();
        };

        // TODO 還可以不預覽,直接異步ajax發送請求到后臺,上傳檔案,然后回傳頁面顯示頭像,并將圖片的路徑防止頁面隱藏域,提交表單記錄頭像的地址
    });
//============  頭像更換 end ================

3.4.2 控制層

1.獲取頭像檔案流,并保存圖片;

2.將圖片地址保存到用戶的頭像中;

3.重繪session中的用戶資訊;

@RequestMapping("/headImg")
public String headImg(HttpSession session,
                      @RequestParam("userHeaderImg") MultipartFile multipartFile,
                      Map<String, String> map) throws IOException {
    // 獲取上傳的頭像檔案名稱
    String targetFileName = multipartFile.getOriginalFilename();
    System.out.println("------ 上傳檔案名:" + targetFileName + " ------");

    // 重新定義新的檔案名,要保留上傳檔案的型別
    targetFileName = UUID.randomUUID().toString().substring(0, 8) + targetFileName.substring(targetFileName.indexOf("."));

    System.out.println("------ 新的檔案名:" + targetFileName + " ------");

    // 上傳檔案,要保存服務器上的真實路徑中,idea專案發布,默認不會放到目標tomcat中,放在本地專案的target目錄中
    String realFilePath = session.getServletContext().getRealPath("img/about");

    System.out.println("------ 服務器真實路徑:" + realFilePath + " ------");

    // 目標檔案目錄可能不存在,不能人為干預,必須程式主動處理
    File targetFilePath = new File(realFilePath);
    if(!targetFilePath.exists()){
        // 目標不存在,主動創建
        if(targetFilePath.mkdirs()){
            System.out.println("------ 上傳目錄創建成功 ------");
        }
    }

    // 創建目標檔案物件
    File targetFile = new File(targetFilePath + "/" + targetFileName);

    // 檔案上傳到服務器,只需要一步,組件自動支持功能
    multipartFile.transferTo(targetFile);

    // 資料庫存入頭像資訊
    targetFileName = "img/about/"+targetFileName;

    //獲取當前登錄用戶物件
    User loginUser =  (User)session.getAttribute(CommConstant.SYS_SESSION_LOGINUSER);

    //換頭像
    loginUser.setUhead(targetFileName);

    //重置 session 中的 用戶物件
    session.setAttribute(CommConstant.SYS_SESSION_LOGINUSER,loginUser);

    // 呼叫 修改用戶資訊 方法,修改用戶資訊
    User userForm = new User();
    userForm.setUid(loginUser.getUid());
    userForm.setUhead(loginUser.getUhead());
    userService.modUserInfo(userForm);

    //放入修改成功提示資訊,可以不提示(操作過后感覺,不回傳效果好些,看時機需求)
    map.put("modUserInfoMsg","用戶頭像修改成功!");

    return "/personCenter";
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/511922.html

標籤:其他

上一篇:深入理解Lambda運算式

下一篇:C++ 如何讀取亂碼檔案內容?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more