第04項目:淘淘商城(SpringMVC+Spring+Mybatis) 的學習實踐總結【第六天】

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040html

第04項目:淘淘商城(SpringMVC+Spring+Mybatis) 的學習實踐總結【第五天】java

第04項目:淘淘商城(SpringMVC+Spring+Mybatis) 的學習實踐總結【第六天】node

 

開發環境:web

Eclipse IDE for Enterprise Java Developers
OS: Windows 10, v.10.0, x86_64 / win32
Java version: 1.8.0_221spring

06.第六天(CMS系統)


 

 

 

須要把內容進行分類,分類應該是一個樹形結構。在展現首頁時,能夠根據分類取內容信息,把內容展現到頁面。apache

在後臺管理內容及內容分類的系統就叫作cms系統。編程

先實現內容的分類管理再實現內容管理。json

3.1    內容分類管理

3.1.1   內容分類初始化

需求分析

初始化樹形視圖的url:/content/category/listapp

參數是id,當前節點id屬性,應該根據此id查詢子節點列表。異步

返回值:包含id、text、state三個屬性的json數據列表

Service層

功能:接收parentid。根據parentid查詢節點列表,返回返回一個EasyUI異步Tree要求的節點列表。每一個節點包含三個屬性id、text、state三個屬性。可使用自定義的EUTreeNode。

參數:id

返回值:List<EUTreeNode>

@Service
public class ContentCategoryServiceImpl implements ContentCategoryService {

    @Autowired
    private TbContentCategoryMapper contentCategoryMapper;
    @Override
    public List<EUTreeNode> getCategoryList(long parentId) {
        //根據parentid查詢節點列表
        TbContentCategoryExample example = new TbContentCategoryExample();
        Criteria criteria = example.createCriteria();
        criteria.andParentIdEqualTo(parentId);
        //執行查詢
        List<TbContentCategory> list = contentCategoryMapper.selectByExample(example);
        List<EUTreeNode> resultList = new ArrayList<>();
        for (TbContentCategory tbContentCategory : list) {
            //建立一個節點
            EUTreeNode node = new EUTreeNode();
            node.setId(tbContentCategory.getId());
            node.setText(tbContentCategory.getName());
            node.setState(tbContentCategory.getIsParent()?"closed":"open");
            
            resultList.add(node);
        }
        return resultList;
    }

}
View Code

Controller

接收頁面傳遞過來的parentid,根據parentid查詢節點列表。返回List<EUTreeNode>。須要響應json數據。

@Controller
@RequestMapping("/content/category")
public class ContentCategoryController {

    @Autowired
    private ContentCategoryService contentCategoryService;
    
    @RequestMapping("/list")
    @ResponseBody
    public List<EUTreeNode> getContentCatList(@RequestParam(value="id", defaultValue="0")Long parentId) {
        List<EUTreeNode> list = contentCategoryService.getCategoryList(parentId);
        return list;
    }
}

3.1.2   內容分類添加

請求的url:/content/category/create

參數:

一、parentId父節點id

二、name:當前節點的名稱

返回值:TaotaoResult。其中包含節點pojo對象。

Service層

功能:接收兩個參數parentId父節點id、name:當前節點的名稱。向tb_content_category表中添加一條記錄。返回TaoTaoResult包含記錄的pojo對象。

須要返回主鍵信息:

須要修改mapper文件,返回主鍵信息。

  <selectKey keyProperty="id" resultType="Long" order="AFTER">
  SELECT LAST_INSERT_ID()
  </selectKey>

 

 

 

@Override
    public TaotaoResult insertContentCategory(long parentId, String name) {
        
        //建立一個pojo
        TbContentCategory contentCategory = new TbContentCategory();
        contentCategory.setName(name);
        contentCategory.setIsParent(false);
        //'狀態。可選值:1(正常),2(刪除)',
        contentCategory.setStatus(1);
        contentCategory.setParentId(parentId);
        contentCategory.setSortOrder(1);
        contentCategory.setCreated(new Date());
        contentCategory.setUpdated(new Date());
        //添加記錄
        contentCategoryMapper.insert(contentCategory);
        //查看父節點的isParent列是否爲true,若是不是true改爲true
        TbContentCategory parentCat = contentCategoryMapper.selectByPrimaryKey(parentId);
        //判斷是否爲true
        if(!parentCat.getIsParent()) {
            parentCat.setIsParent(true);
            //更新父節點
            contentCategoryMapper.updateByPrimaryKey(parentCat);
        }
        //返回結果
        return TaotaoResult.ok(contentCategory);
    }

 

Controller層

接收兩個參數parentid、name。調用Service添加記錄。返回TaotaoResult。應該返回json數據。

@RequestMapping("/create")
    @ResponseBody
    public TaotaoResult createContentCategory(Long parentId, String name) {
        TaotaoResult result = contentCategoryService.insertContentCategory(parentId, name);
        return result;
    }

 

 

3.2  內容管理

內容管理表:

3.2.2   內容添加

需求分析:

 

 內容表單提交:

 

請求的url:/content/save

請求的方法:post

請求內容:表單中的內容

返回的結果:TaotaoResult

Dao層

向tb_content表中插入數據。可使用逆向工程生成的代碼。

Service層

接收表tb_content對應的pojo對象。把pojo對象插入到tb_content表中。

返回TaotaoResult。

@Service
public class ContentServiceImpl implements ContentService {

    @Autowired
    private TbContentMapper  contentMapper;
    
    @Override
    public TaotaoResult insertContent(TbContent content) {
        //補全pojo內容
        content.setCreated(new Date());
        content.setUpdated(new Date());
        contentMapper.insert(content);
        
        return TaotaoResult.ok();
    }

}

Controller層

接收表單中的內容,使用pojo接收。要求pojo的屬性要和表單中的name一致。調用Service插入內容信息。返回TaotaoResult。Json格式的數據。

@Controller
@RequestMapping("/content")
public class ContentController {

    @Autowired
    private ContentService contentService;
    
    @RequestMapping("/save")
    @ResponseBody
    public TaotaoResult insertContent(TbContent content) {
        TaotaoResult result = contentService.insertContent(content);
        return result;
    }
}
View Code

3.2.1   內容列表

需求分析:根據內容分類id查詢內容列表。須要實現分頁。

請求url:/content/query/list

參數:page、rows、categoryId

返回值類型:EUDataGridResult

Total、rows:內容pojo列表。

    //查詢內容列表並分頁
    @Override
    public EUDataGridResult queryContentList(Long categoryId, int page, int rows) {
        //使用分頁插件處理分頁
        PageHelper.startPage(page, rows);//使用逆向工程的條件查詢
        TbContentExample example = new TbContentExample();
        Criteria criteria = example.createCriteria();
        criteria.andCategoryIdEqualTo(categoryId);
        List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);
        //獲取分頁插件信息
        PageInfo<TbContent> pageInfo = new PageInfo<TbContent>(list); //
        EUDataGridResult result = new EUDataGridResult();
        result.setTotal(pageInfo.getTotal());
        result.setRows(list);
        
        return result;
    }

 Controller層

    @RequestMapping("/query/list")
    @ResponseBody
    public EUDataGridResult queryContentList(Long categoryId ,int page,int rows) {
        
        return contentService.queryContentList(categoryId, page, rows);
        
    }
View Code

3.2.6 內容的刪除

請求url:/content/delete

請求的方法:post

請求參數:ids

返回的結果:TaotaoResult

圖片位置:content.jsp

 

Service層

    @Override
    //刪除內容根據ids
    public TaotaoResult deleteContent(Long contentId) {
        //建立查詢條件
        TbContentExample example = new TbContentExample();
        TbContentExample.Criteria criteria = example.createCriteria();
        criteria.andIdEqualTo(contentId);
        //執行刪除        
        contentMapper.deleteByExample(example);
        
        return TaotaoResult.ok();
    }
    

Controller層

    //刪除選中內容
    @RequestMapping("/delete")
    @ResponseBody
    public TaotaoResult deleteContent(@RequestParam("ids")Long contentId ) {
        TaotaoResult result = contentService.deleteContent(contentId);

        return result;
        
    }

 3.1.3 內容分類的刪除

Controller層

    //內容分類管理:刪除
    @RequestMapping("/delete")
    @ResponseBody
    public TaotaoResult deleteContentCategory( Long id ) {
        TaotaoResult result = contentCategoryService.deleteContentCategory(id);
        
        return result;
    }

Service層

    @Autowired
    private TbContentCategoryMapper contentCategoryMapper;
    
    
    @Override
    public TaotaoResult deleteContentCategory(long id) {
        deleteCategoryAndChildNode(id);
        return TaotaoResult.ok();
    }

    private List<TbContentCategory> getChildNodeList(Long id) {
        //查詢全部父節點ID爲傳入id的內容分類
        TbContentCategoryExample example = new TbContentCategoryExample();
        TbContentCategoryExample.Criteria criteria = example.createCriteria();
        criteria.andParentIdEqualTo(id);
        //查詢結果做爲返回值
        return contentCategoryMapper.selectByExample(example);        
    }
    
    // 根據ID刪除葉子分類節點和本身的節點並判斷父節點屬性
    private void deleteCategoryAndChildNode(Long id) {

        TbContentCategory tcc = contentCategoryMapper.selectByPrimaryKey(id);
        // 1.刪除全部該分類下的子節點
        if (tcc.getIsParent()) {
            // 查詢該節點下的孩子節點
            List<TbContentCategory> list = getChildNodeList(id);
            // 刪除全部孩子節點
            for (TbContentCategory contentCategory : list) {
                // 遞歸調用本方法本身
                deleteCategoryAndChildNode(contentCategory.getId());
            }
        }
        // 2.判斷刪除完成後,父節點下是否還有其餘子節點
        List<TbContentCategory> list = getChildNodeList(tcc.getParentId());
        if (CollectionUtils.isEmpty(list)) {
            TbContentCategory parentCategory = contentCategoryMapper.selectByPrimaryKey(tcc.getParentId());
            parentCategory.setIsParent(false);
            contentCategoryMapper.updateByPrimaryKey(parentCategory);
        }

        // 3.刪除本節點
        contentCategoryMapper.deleteByPrimaryKey(id);

        return;
    }

 


4.1    首頁大廣告方案

 

優勢:有利於seo優化。能夠在taotao-portal中對數據進行加工。

缺點:系統直接須要調用服務查詢內容信息。多了一次http請求。

系統直接服務的調用,須要使用httpclient來實現。Taotao-portal和taotao-rest是在同一個局域網內部。速度很是快,調用時間能夠忽略不計。

4.2    展現流程

 

 

 

4.3    內容服務發佈

4.3.1   需求分析

根據內容的分類id查詢內容列表,從tb_content表中查詢。服務是一個restFul形式的服務。使用http協議傳遞json格式的數據。

4.3.2   Dao層

從tb_content表中查詢,根據內容分類id查詢。是單表查詢。可使用逆向工程生成的代碼。

4.3.3   Service層

接收內容分類id,根據分類id查詢分類列表。返回一個內容pojo列表。

參數:分類id

返回值:pojo列表

taotao-rest工程

/**
 * 內容管理
 * @author kangy
 *
 */
@Service
public class ContentServiceImpl implements ContentService {
    @Autowired
    private TbContentMapper contentMapper;

    @Override
    public List<TbContent> getContentList(long contentCid) {
        // 根據內容分類id查詢內容列表
        TbContentExample example = new TbContentExample();
        TbContentExample.Criteria criteria = example.createCriteria();
        criteria.andCategoryIdEqualTo(contentCid);
        //執行查詢
        List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);
        
        //返回結果
        return list;
    }

}
View Code ContentServiceImpl

4.3.4   Controller層

發佈服務。接收查詢參數。Restful風格內容分類id應該從url中取。

/rest/content/list/{contentCategoryId}

從url中取內容分類id,調用Service查詢內容列表。返回內容列表。返回一個json格式的數據。可使用TaotaoResult包裝此列表。

@RestController
@RequestMapping("/content")
public class ContentController {

    @Autowired
    private ContentService contentService;

    @GetMapping("/list/{contentCategoryId}")
    public TaotaoResult getContentList(@PathVariable Long contentCategoryId) {

        try {
            List<TbContent> list = contentService.getContentList(contentCategoryId);
            return TaotaoResult.ok(list);
        } catch (Exception e) {
            e.printStackTrace();
            // 調用自定義工具類的靜態方法
            return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }

    }

}
package com.taotao.common.utils;

import java.io.PrintWriter;
import java.io.StringWriter;

public class ExceptionUtil {

    /**
     * 獲取異常的堆棧信息
     * 
     * @param t
     * @return
     */
    public static String getStackTrace(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);

        try {
            t.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }
}
View Code

 

 

http://localhost:8081/rest/content/list/89

 


 

4.4    Httpclient的使用

4.4.1   什麼是httpclient

HttpClient 是 Apache 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,而且它支持 HTTP 協議最新的版本和建議。
下載地址:

http://hc.apache.org/

4.4.2   添加依賴

須要把httpclient的jar包添加到工程中。只須要在工程中添加httpclient的依賴。

        <!-- httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>

12.httpclient執行get請求

使用httpclient執行get請求

@Test
    public void doGet() throws Exception {
        //建立一個httpclient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //建立一個GET對象
        HttpGet get = new HttpGet("http://www.sogou.com");
        //執行請求
        CloseableHttpResponse response = httpClient.execute(get);
        //取響應的結果
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println(statusCode);
        HttpEntity entity = response.getEntity();
        String string = EntityUtils.toString(entity, "utf-8");
        System.out.println(string);
        //關閉httpclient
        response.close();
        httpClient.close();
    }

執行get請求帶參數

@Test
    public void doGetWithParam() throws Exception{
        //建立一個httpclient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //建立一個uri對象
        URIBuilder uriBuilder = new URIBuilder("http://www.sogou.com/web");
        uriBuilder.addParameter("query", "花千骨");
        HttpGet get = new HttpGet(uriBuilder.build());
        //執行請求
        CloseableHttpResponse response = httpClient.execute(get);
        //取響應的結果
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println(statusCode);
        HttpEntity entity = response.getEntity();
        String string = EntityUtils.toString(entity, "utf-8");
        System.out.println(string);
        //關閉httpclient
        response.close();
        httpClient.close();
    }

 

使用httpclient執行post請求

@Test
    public void doPost() throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
    
        //建立一個post對象
        HttpPost post = new HttpPost("http://localhost:8082/httpclient/post.html");
        //執行post請求
        CloseableHttpResponse response = httpClient.execute(post);
        String string = EntityUtils.toString(response.getEntity());
        System.out.println(string);
        response.close();
        httpClient.close();
        
    }

帶參數post請求

@Test
    public void doPostWithParam() throws Exception{
        CloseableHttpClient httpClient = HttpClients.createDefault();
        
        //建立一個post對象
        HttpPost post = new HttpPost("http://localhost:8082/httpclient/post.html");
        //建立一個Entity。模擬一個表單
        List<NameValuePair> kvList = new ArrayList<>();
        kvList.add(new BasicNameValuePair("username", "zhangsan"));
        kvList.add(new BasicNameValuePair("password", "123"));
        
        //包裝成一個Entity對象
        StringEntity entity = new UrlEncodedFormEntity(kvList, "utf-8");
        //設置請求的內容
        post.setEntity(entity);
        
        //執行post請求
        CloseableHttpResponse response = httpClient.execute(post);
        String string = EntityUtils.toString(response.getEntity());
        System.out.println(string);
        response.close();
        httpClient.close();
    }

4.4.4   Httpclient封裝成工具類

其餘項目也可能會用到httpclient,因此把工具類放到taotao-common中。

package com.taotao.common.utils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class HttpClientUtil {

    public static String doGet(String url, Map<String, String> param) {

        // 建立Httpclient對象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 建立uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 建立http GET請求
            HttpGet httpGet = new HttpGet(uri);

            // 執行請求
            response = httpclient.execute(httpGet);
            // 判斷返回狀態是否爲200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, String> param) {
        // 建立Httpclient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 建立Http Post請求
            HttpPost httpPost = new HttpPost(url);
            // 建立參數列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模擬表單
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 執行http請求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }
    
    public static String doPostJson(String url, String json) {
        // 建立Httpclient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 建立Http Post請求
            HttpPost httpPost = new HttpPost(url);
            // 建立請求內容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 執行http請求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }
}
HttpClientUtil

 

5   大廣告位展現

5.1    需求分析

須要建立一個json字符串傳遞給jsp:

 

 

Json字符串如何傳遞給jsp:使用modelAndView對象把json字符串傳遞給jsp。

如何得到json字符串:得到一個廣告位對應的內容列表,須要調用taotao-rest的服務。把列表轉換成json數據格式要求的pojo對象列表。

須要使用httpclient調用taotao-rest的服務。

taotao-portal項目子模塊

 

package com.taotao.portal.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.HttpClientUtil;
import com.taotao.common.utils.JsonUtils;
import com.taotao.pojo.TbContent;
import com.taotao.portal.service.ContentService;

/**
 * 調用服務層服務,查詢內容列表
 * 
 * @author kangy
 *
 */
@Service
public class ContentServiceImpl implements ContentService {

    @Value("${REST_BASE_URL}")
    private String REST_BASE_URL;
    @Value("${REST_INDEX_AD_URL}")
    private String REST_INDEX_AD_URL;

    @Override
    public String getContentlist() {
        // 調用服務層服務
        String result = HttpClientUtil.doGet(REST_BASE_URL + REST_INDEX_AD_URL);
        // 把字符串轉換成TaotaoResult
        try {
            TaotaoResult taotaoResult = TaotaoResult.formatToList(result, TbContent.class);
            // 取內容列表
            List<TbContent> list = (List<TbContent>) taotaoResult.getData();
            List<Map> resultList = new ArrayList<Map>();
            // 建立一個jsp頁碼要求的pojo列表
            for (TbContent tbContent : list) {
                Map map = new HashMap<>();
                map.put("src", tbContent.getPic());
                map.put("height", 240);
                map.put("width", 670);
                map.put("srcB", tbContent.getPic2());
                map.put("widthB", 550);
                map.put("height", 240);
                map.put("href", tbContent.getUrl());
                map.put("alt", tbContent.getSubTitle());
                resultList.add(map);

            }

            return JsonUtils.objectToJson(resultList);

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

    }

}

 

package com.taotao.common.utils;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.taotao.common.pojo.TaotaoResult;

/**
 * 淘淘商城自定義響應結構
 */
public class JsonUtils {

    // 定義jackson對象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 將對象轉換成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
        try {
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 將json結果集轉化爲對象
     * 
     * @param jsonData json數據
     * @param clazz 對象中的object類型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 將json數據轉換成pojo對象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
}
淘淘商城自定義響應結構

 

@Controller
public class IndexController {
    @Autowired
    private ContentService contentService;

    @RequestMapping("/index")
    public String showIndex(Model model) {
        String adJson = contentService.getContentlist();
        model.addAttribute("ad1", adJson);
        
        return"index";
    }
}

 

==============================================

參考資料:

淘淘商城-內容分類管理 修改、刪除實現、內容列表展現

@RequestParam、@RequestBody和@ModelAttribute區別

end 

相關文章
相關標籤/搜索