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

来源:https://www.cnblogs.com/xiaoqigui/archive/2022/10/09/16772636.html
-Advertisement-
Play Games

1、支付寶沙箱 1.1 jar包 alipay-sdk <!-- alipay-sdk --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.10. ...


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 = "/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="${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";
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 數據結構基礎—棧和隊列 一、棧和隊列的基本概念和性質 棧和隊列都是特殊的線性表 對他們的操作有著規定和限制:在插入和刪除時只能對某一端操作 棧:只能在一端進行(先進後出) 隊列:只能在表尾插入,在表頭刪除(先進先出) 二、棧 表頭為棧底,表尾為棧頂 1.棧的基本操作和規則 a.進棧和出棧 進棧:棧頂 ...
  • 垃圾回收器 垃圾回收是釋放掉那些不再被使用的記憶體空間的過程。 換句話說,垃圾回收器會去檢查哪些對象超出範圍並且不會再被引用到,然後它回去釋放掉那些對象占用的記憶體空間。這個過程實在 go 程式運行中以併發的方式去進行的,不是 go 程式執行之前,也不是 go 程式執行之後。go 垃圾回收器實現的說明文 ...
  • 前幾天看報道說: 一位小哥用AI繪畫工具Midjourney生成的作品,在美國科羅拉多州博覽會的藝術比賽中獲得了第一名。 作者表示,他多次調整了輸入的提示詞,生成了100多幅畫作,經過數周的修改和挑選,才選出了三幅最滿意的作品。 下圖就是獲獎作品 之前我玩過DF,還寫過一篇文章➡️AI繪畫 Disc ...
  • python 有許多可視化工具,但本書只介紹Matplotlib。Matplotlib是一種2D的繪圖庫,它可以支持硬拷貝和跨系統的交互,它可以在python腳本,IPython的交互環境下、Web應用程式中使用。該項目是由John Hunter 於2002年啟動,其目的是為python構建MATL ...
  • STL和c++標準庫 標準模板庫STL部分包含在C++標準庫中的軟體庫。 c++標準庫:即以std::開頭,但是部分編譯器廠商也會把STL的內容放在std:: namespace裡面 由於一個常見的誤解,您可能會將C++標準庫視為“STL”,或者將工具鏈中C++標準庫的實現部分視為“STL實現”。 ...
  • IoC容器的實現學習——01 簡介 在以前通常情況下一個簡單的項目一般由兩個及兩個以上的類構成,大多數的類集數據和數據的處理方法於一體,類之間通過依賴彼此的數據和方法實現業務邏輯,這個獲取依賴的過程是自己實現的,導致代碼高度耦合以及難以測試。 所以出現了DI (依賴註入)、IoC (控制反轉) 這些 ...
  • java基礎-文件與IO 以下內容為本人的學習筆記,如需要轉載,請聲明原文鏈接 https://www.cnblogs.com/lyh1024/p/16772853.html IO是一個龐大的體系,信息傳遞的通道靠IO,例如:文件讀寫、上傳下載、網路通信等都要用到。 1.File類的基本概念 Fil ...
  • 本人近期在做國創項目,其中需要使用重覆碼,並且使用經過重覆碼編碼後的數據進行加密。 問題是重覆碼編碼後再讀取就亂碼了,而且我不知道怎麼樣可以讀取出二進位數據 重覆碼代碼如下: #include<iostream> #include<stdlib.h> #include<string> #includ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...