4、商品修改功能開發(fā)(springmvc筆記)

主要內(nèi)容:

  • RequestMapping特性
  • Controller方法返回值
  • 參數(shù)綁定

一、需求分析

這里我們還是使用上次整合的工程。
操作流程:

  • (1)進(jìn)入商品查詢列表頁(yè)面
  • (2)點(diǎn)擊修改,進(jìn)入商品修改頁(yè)面,頁(yè)面中顯示了要修改的商品信息(從數(shù)據(jù)庫(kù)中查詢),要修改的商品從數(shù)據(jù)查詢,根據(jù)商品id(主鍵)查詢商品信息
  • (3)在商品修改頁(yè)面,修改商品信息,修改后,點(diǎn)擊提交。

二、開發(fā) mapper

根據(jù)上面的需求我們可以知道,mapper中此處需要完成兩個(gè)功能:

  • 根據(jù)id查詢商品信息,返回給頁(yè)面顯示
  • 更新items表的數(shù)據(jù),更新數(shù)據(jù)庫(kù)
    但是這里的兩個(gè)功能需求是相對(duì)簡(jiǎn)單的,在逆向工程中已經(jīng)幫我們生成好了相關(guān)代碼,我們只需要直接使用即可,不需要再次開發(fā)。

三、開發(fā) service

根據(jù)持久層mapper的相關(guān)業(yè)務(wù)需求,這里我們就可以知道業(yè)務(wù)層的功能需求

  • 根據(jù)id查詢商品信息
  • 修改商品信息

3.1 接口

ItemsServiceI.java

//根據(jù)id查詢商品信息
public ItemsCustom findItemsById(Integer id) throws Exception;
    
//修改商品信息,這里id本來(lái)已經(jīng)在itemsCustom存在,但是為了更好的開發(fā),還是將id提取出來(lái)
//作為一個(gè)參數(shù),表明此id必須傳入
public void updateItems(Integer id, ItemsCustom itemsCustom) throws Exception;

3.2 實(shí)現(xiàn)

ItemsServiceImpl.java

package cn.itcast.ssm.service.impl;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import cn.itcast.ssm.mapper.ItemsMapper;
import cn.itcast.ssm.mapper.ItemsMapperCustom;
import cn.itcast.ssm.pojo.Items;
import cn.itcast.ssm.pojo.ItemsCustom;
import cn.itcast.ssm.pojo.ItemsQueryVo;
import cn.itcast.ssm.service.ItemsServiceI;

public class ItemsServiceImpl implements ItemsServiceI{
    
    @Autowired
    private ItemsMapperCustom itemsMapperCustom;
    @Autowired
    private ItemsMapper itemsMapper;
    
    @Override
    public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo)
            throws Exception {
        //通過(guò)ItemsMapperCustom查詢數(shù)據(jù)庫(kù),通過(guò)spring注入
        return itemsMapperCustom.findItemsList(itemsQueryVo);
    }

    @Override
    public ItemsCustom findItemsById(Integer id) throws Exception { 
        Items items = itemsMapper.selectByPrimaryKey(id);
        //查詢出來(lái)的數(shù)據(jù)可能需要進(jìn)行一些業(yè)務(wù)處理,最后要返回ItemsCustom
        ItemsCustom itemsCustom = new ItemsCustom();
        //將Items內(nèi)容拷貝到ItemsCustom
        BeanUtils.copyProperties(items, itemsCustom);
        
        return itemsCustom;
    }

    @Override
    public void updateItems(Integer id, ItemsCustom itemsCustom) throws Exception {
        //添加一些業(yè)務(wù)校驗(yàn),通常在service接口對(duì)關(guān)鍵的參數(shù)進(jìn)行校驗(yàn)
        //校驗(yàn)id是否為空等等,如果為空則拋出異常
        
        
        //更新商品信息,使用updateByPrimaryKeyWithBLOBs可以根據(jù)id更新表中所有字段,
        //包括大文本字段,這里因?yàn)楸碇杏袀€(gè)字段屬性為text,所以使用此方法
        //要求必須傳入id,即使類中已經(jīng)存在
        itemsCustom.setId(id);
        itemsMapper.updateByPrimaryKeyWithBLOBs(itemsCustom);
    }
}

說(shuō)明:這里我們的方法還不是很完善,比如這里就沒(méi)有給出查詢條件,在后面一步步完善。

四、開發(fā)Controller

ItemsController.java

package cn.itcast.ssm.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import cn.itcast.ssm.pojo.ItemsCustom;
import cn.itcast.ssm.service.ItemsServiceI;
//商品Controller

@Controller
public class ItemsController {
    
    @Autowired
    private ItemsServiceI itemsService;
    
    //商品查詢
    @RequestMapping("/queryItems")
    public ModelAndView queryItems() throws Exception{
        List<ItemsCustom> itemsList = itemsService.findItemsList(null);//這里暫時(shí)還沒(méi)有查詢條件
        
        //返回ModelAndView
        ModelAndView modelAndView = new ModelAndView();
        //相當(dāng)于request的setAttribute方法,在jsp頁(yè)面中就可以通過(guò)items取數(shù)據(jù)了
        modelAndView.addObject("itemsList",itemsList);
        
        //指定視圖
        modelAndView.setViewName("items/itemsList");
        
        return modelAndView;
    }
    //商品信息修改頁(yè)面展示
    @RequestMapping("/editItems")
    public ModelAndView editItems() throws Exception{
        //調(diào)用service根據(jù)id查詢商品信息
        ItemsCustom itemsCustom = itemsService.findItemsById(1);
        
        ModelAndView modelAndView = new ModelAndView();
        //將商品信息放入Model
        modelAndView.addObject("itemsCustom", itemsCustom);
        
        //返回商品修改頁(yè)面
        modelAndView.setViewName("items/editItems");
        
        return modelAndView;
    }
    
    
    //商品修改提交
    @RequestMapping("/editItemsSubmit")
    public ModelAndView editItemsSubmit() throws Exception{
        //調(diào)用service更新商品信息,頁(yè)面需要將商品信息傳到此方法
        //............
        
        ModelAndView modelAndView = new ModelAndView();
        //先返回一個(gè)成功頁(yè)面
        
        //返回商品修改頁(yè)面
        modelAndView.setViewName("success");
        
        return modelAndView;
    }
}

說(shuō)明:對(duì)于商品列表展示頁(yè)面在整合工程中已經(jīng)給出,這里我們給出修改頁(yè)面:
WEB-INF/jsp/items/editItems.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
    isELIgnored="false"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改商品信息</title>
</head>
<body>
    <form id="itemForm" action="${pageContext.request.contextPath }/editItemsSubmit.action"
        method="post">
        <input type="hidden" name="id" value="${itemsCustom.id }" /> 修改商品信息:
        <table width="100%" border=1>
            <tr>
                <td>商品名稱</td>
                <td><input type="text" name="name" value="${itemsCustom.name }" /></td>
            </tr>
            <tr>
                <td>商品價(jià)格</td>
                <td><input type="text" name="price" value="${itemsCustom.price }" /></td>
            </tr>
            <tr>
                <td>商品簡(jiǎn)介</td>
                <td><textarea rows="3" cols="30" name="detail">${itemsCustom.detail }</textarea></td>
            </tr>
            <tr>
                <td colspan="2" align="center"><input type="submit" value="提交" /></td>
            </tr>
        </table>
    </form>
</body>
</html>

下面我們就可以部署工程,使用地址http://localhost:8080/springmvc-mybatis01/queryItems.action進(jìn)行訪問(wèn),此時(shí)點(diǎn)擊頁(yè)面中的修改頁(yè)面,就會(huì)找到editItems.action,我們可以看到修改頁(yè)面中回顯了我們選擇要修改商品的信息。當(dāng)然這里還有一個(gè)成功頁(yè)面WEB-INF/jsp/items/success.jsp

五、RequestMapping特性

5.1 普通 url 地址映射

普通url地址映射在之前講過(guò),比如:

@RequestMapping("/queryItems")

5.2 窄化請(qǐng)求映射

所謂窄化請(qǐng)求映射就是當(dāng)控制器中方法很多,映射很多的時(shí)候,我們?yōu)榱吮阌诠芾?,一般?huì)將這些url地址進(jìn)行分類管理。這里我們對(duì)控制器進(jìn)行改造,窄化請(qǐng)求映射。

1.png

這里我們使用:

@RequestMapping("/items")

進(jìn)行窄化請(qǐng)求映射,于是最終的url就是跟路徑+子路徑,比如/items/queryItems.action。我們?cè)诖颂幐膭?dòng)之后需要對(duì)jsp頁(yè)面進(jìn)行改進(jìn),在itemsList.jsp

<td><a href="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a></td>
<%-- <td><a href="${pageContext.request.contextPath }/editItems.action?id=${item.id}">修改</a></td> --%>

editItems.jsp

<form id="itemForm" action="${pageContext.request.contextPath }/items/editItemsSubmit.action" method="post">
<%-- <form id="itemForm" action="${pageContext.request.contextPath }/editItemsSubmit.action" method="post"> --%>

其中被注釋掉的是之前的方式。

5.3 限制 http 請(qǐng)求方法

一般常用請(qǐng)求方式有GETPOST兩種,但是有時(shí)候我們需要規(guī)定必須使用哪種方式,在ItemsController.java:

@RequestMapping(value="/editItems", method={RequestMethod.POST, RequestMethod.GET})
public ModelAndView editItems() throws Exception{

這里我們限制請(qǐng)求方式必須是GET或者POST,當(dāng)然如果這里我們限制為POST,那么默認(rèn)的GET提交方式就提交不成功。

六、Controller方法的返回值

6.1 返回 ModelAndView

這個(gè)在之前我們已經(jīng)講過(guò),這里不再說(shuō)明。

6.2 返回 String

  • 1.返回String
    如果Controller方法返回的是String,表示返回邏輯視圖名。而真正視圖(jsp)=前綴+邏輯視圖名+后綴
@RequestMapping(value="/editItems", method={RequestMethod.POST, RequestMethod.GET})
public String editItems(Model model) throws Exception{
    //調(diào)用service根據(jù)id查詢商品信息
    ItemsCustom itemsCustom = itemsService.findItemsById(1);
    //通過(guò)形參中的model將model數(shù)據(jù)傳遞到頁(yè)面
    //相當(dāng)于modelAndView.addObject("itemsCustom", itemsCustom);
    model.addAttribute("itemsCustom", itemsCustom);
    return "items/editItems";
}

說(shuō)明:可以看到我們首先將數(shù)據(jù)存入到Model中,然后返回邏輯視圖地址。而真正的視圖(jsp)還需要加上前綴和后綴。

  • 2.redirect重定向
    需求:商品修改成功之后重定向到商品查詢列表。修改提交的request數(shù)據(jù)無(wú)法傳遞到重定向的地址。因?yàn)橹囟ㄏ蚝笾匦逻M(jìn)行request,也就是重定向不能共享request。
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit() throws Exception{
    //調(diào)用service更新商品信息,頁(yè)面需要將商品信息傳到此方法
    //............
    
    //ModelAndView modelAndView = new ModelAndView();
    //先返回一個(gè)成功頁(yè)面
    
    //返回商品修改頁(yè)面
    //modelAndView.setViewName("success");
    
    //重定向
    return "redirect:queryItems.action";//根路徑不需要加
    //return "success";
}

說(shuō)明:一定注意在Controller方法中重定向時(shí)不需要加根路徑。

  • 3.forward請(qǐng)求轉(zhuǎn)發(fā)
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit() throws Exception{
    return "forward:queryItems.action";
}

說(shuō)明:通過(guò)此種方式進(jìn)行頁(yè)面轉(zhuǎn)發(fā),url地址欄不變,request可以共享。當(dāng)然我們說(shuō)request可以共享,那么我們可以給方法傳遞一個(gè)參數(shù)HttpServletRequest

@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(HttpServletRequest request) throws Exception{
    return "forward:queryItems.action";
}

于是我們?cè)谄涮D(zhuǎn)的方法中可以接收request

//商品查詢
@RequestMapping("/queryItems")
public ModelAndView queryItems(HttpServletRequest request) throws Exception{
        //測(cè)試request共享
        System.out.println(request.getParameter("id"));
......
}

這樣就實(shí)現(xiàn)了request的共享。我們可以在此方法中進(jìn)行測(cè)試。

6.3 返回 void

Controller方法行參上可以定義requestresponse,使用request或者response指定響應(yīng)結(jié)果:

  • 1)、使用request轉(zhuǎn)向頁(yè)面,如下:
request.getRequestDispatcher("").forward(request, response);
  • 2)、也可以通過(guò)response頁(yè)面重定向
response.sendRedirect("url");
  • 3)、也可以通過(guò)response指定相應(yīng)結(jié)果,例如響應(yīng)json數(shù)據(jù)如下:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");

七、參數(shù)綁定(工程springmvc-mybatis02

7.1 參數(shù)綁定過(guò)程

  • 從客戶端請(qǐng)求key/value數(shù)據(jù),經(jīng)過(guò)參數(shù)綁定,將key/value數(shù)據(jù)綁定到Controller方法的形參上,接收頁(yè)面提交的數(shù)據(jù)是通過(guò)方法的形參,而不是在Controller類定義成員變量。

  • 處理器適配器調(diào)用springmvc提供參數(shù)綁定組件將key/value數(shù)據(jù)轉(zhuǎn)成Controller方法的形參。

  • 參數(shù)綁定組件:在springmvc早起版本使用PropertyEditor(只能將字符串轉(zhuǎn)成java對(duì)象),后期使用converter(進(jìn)行任意參數(shù)類型的轉(zhuǎn)換)。springmvc提供 了很多converter(轉(zhuǎn)換器)。在特殊情況下需要自定義converter(比如對(duì)日期數(shù)據(jù)的綁定需要自定義)。然后調(diào)用Controller。

7.2 參數(shù)綁定默認(rèn)支持的類型

直接在Controller方法的形參上定義下面類型的對(duì)象,就可以使用這些對(duì)象。在參數(shù)綁定過(guò)程中,如果遇到下邊的類型直接進(jìn)行綁定(自動(dòng)進(jìn)行的)。

  • 1)、HttpServletRequest
    通過(guò)request對(duì)象獲取請(qǐng)求信息

  • 2)HttpServletResponse
    通過(guò)response處理響應(yīng)信息

  • 3)HttpSession
    通過(guò)session對(duì)象得到session中存放的對(duì)象。

  • 4)Model/ModelMap
    Model是一個(gè)接口,ModelMap是接口實(shí)現(xiàn)。在Controller方法形參中我們可以定義成前者或者后者都行。作用:將模型數(shù)據(jù)填充到request域。

7.3 綁定簡(jiǎn)單類型

public String editItems(Model model, @RequestParam(value="id", required=true, defaultValue="") Integer items_id)

說(shuō)明:這里我們綁定了一個(gè)簡(jiǎn)單類型(Integer),如果這個(gè)參數(shù)名稱為id,也就是和request傳入?yún)?shù)名稱一致,那么我們不需要使用注解。但是這里我們參數(shù)名稱是items_id,也就是不一致,那么我們需要使用上面的注解進(jìn)行綁定。@RequestParamvalue指定request傳入?yún)?shù)名稱和形參綁定,required=true指定此參數(shù)是否必須被傳入,defaultValue=""設(shè)置默認(rèn)值??梢越壎ǖ暮?jiǎn)單類型還有String、float、double、boolean。

7.4 綁定 pojo 對(duì)象

@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(HttpServletRequest request, Integer id, ItemsCustom itemsCustom) throws Exception{
    
    itemsService.updateItems(id, itemsCustom);
    
    return "forward:queryItems.action";
}

說(shuō)明:這里我們綁定pojo類有個(gè)前提,就是頁(yè)面中input的名稱和Controllerpojo形參中的屬性名稱一致,可以自動(dòng)將頁(yè)面中的數(shù)據(jù)綁定到pojo

  • 問(wèn)題一:亂碼問(wèn)題
    • POST亂碼
      web.xml中添加post亂碼過(guò)濾器:
<!-- post亂碼過(guò)慮器 -->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • GET亂碼
    對(duì)于get請(qǐng)求中文參數(shù)中出現(xiàn)亂碼解決方法有兩個(gè):
    1.修改tomcat配置文件(server.xml)添加編碼與工程一致,如下:
    1

    2.另一種方法對(duì)參數(shù)進(jìn)行重新編碼:
String username = new String(request.getParameter("username").getBytes("iso8859-1"),"utf-8");
  • 問(wèn)題二:日期類型的綁定問(wèn)題
    我們將editItems.jsp中這段代碼的注釋去掉:
<tr>
    <td>商品生產(chǎn)日期</td>
    <td><input type="text" name="createtime" value="<fmt:formatDate value="${itemsCustom.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
</tr>

然后我們?cè)俅卧L問(wèn)時(shí)發(fā)生錯(cuò)誤,這里的問(wèn)題是日期類型不能自動(dòng)綁定,需要我們手動(dòng)編寫轉(zhuǎn)換器之后綁定。對(duì)于Controller形參中pojo對(duì)象,如果屬性中有日期類型,需要自定義參數(shù)綁定。將請(qǐng)求的日期數(shù)據(jù)串轉(zhuǎn)換成日期類型,要轉(zhuǎn)換的日期類型和pojo中日期屬性的類型保持一致。需要像處理器適配器中注入自定義的參數(shù)綁定組件。在springmvc.xml中:

<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

<!-- 自定義參數(shù)綁定 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <!-- 轉(zhuǎn)換器 -->
    <property name="converters">
        <list>
            <!-- 日期類型的轉(zhuǎn)換 -->
            <bean class="cn.itcast.ssm.controller.convert.CustomDateConverter"></bean>
            <!-- 其他類型的轉(zhuǎn)換 -->
        </list>
    </property>
</bean>

說(shuō)明:我們使用conversion-service屬性給適配器中添加自定義轉(zhuǎn)換器。
自定義轉(zhuǎn)換器CustomDateConverter.java

package cn.itcast.ssm.controller.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;

public class CustomDateConverter implements Converter<String, Date>{

    @Override
    public Date convert(String source) {
        //實(shí)現(xiàn)將日期字符串轉(zhuǎn)換成日期類型(格式是yyyy-MM-dd HH:mm:ss)
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            //如果轉(zhuǎn)換成功
            return format.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //如果綁定失敗
        return null;
    }
}

說(shuō)明:注意自定義轉(zhuǎn)換器需要實(shí)現(xiàn)Converter接口。其中String是我們需要轉(zhuǎn)換的類型,Date是我們最終需要的類型。

  • 最后:上面我們是將適配器和映射器配置在一起,可能不太容易理解,如果單獨(dú)配置,那么我們的轉(zhuǎn)換器配置應(yīng)該如下:
<!--注解適配器 -->
    <bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
         <property name="webBindingInitializer" ref="customBinder"></property> 
    </bean>
    
    <!-- 自定義webBinder -->
    <bean id="customBinder"
        class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
        <property name="conversionService" ref="conversionService" />
    </bean>
    <!-- conversionService -->
    <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 轉(zhuǎn)換器 -->
        <property name="converters">
            <list>
                <bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
            </list>
        </property>
    </bean>

當(dāng)然這種方式較為繁瑣,這里只是了解。

八、springmvc 和 struts2的區(qū)別

  • 1、springmvc基于方法開發(fā)的,struts2基于類開發(fā)的。springmvc映射時(shí)將urlController方法進(jìn)行映射。映射成功之后springmvc會(huì)生成一個(gè)handler對(duì)象,對(duì)象中只包括了一個(gè)method,方法執(zhí)行結(jié)束,形參數(shù)據(jù)就銷毀了。springmvcController開發(fā)類似service開發(fā)。

  • 2、springmvc可以進(jìn)行單例開發(fā),并且也建議單例開發(fā)。Struts2通過(guò)類的成員變量接收的參數(shù),所以無(wú)法使用單例,只能使用多例。

  • 3、struts2速度慢在于使用struts2標(biāo)簽。建議,如果使用struts2,直接使用jstl,不要使用struts2的標(biāo)簽。

最后:我們看到這里我們使用這樣一個(gè)例子將springmvc開發(fā)中所需要用到的一些基本內(nèi)容說(shuō)明了,對(duì)于其他功能開發(fā)基本就類似了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容