Spring @SessionAttributes @ModelAttribute

最近在幫企業作微信企業號的項目,關於用戶查詢工資條這一塊的問題。只要以前有一我的查詢了工資,我再查詢的時候總是能夠查詢到他的工資信息。沒有太想明白問題的緣由啊。貌似我經過加上@SessionAttributes就沒有發生查詢到別人的工資的問題了。另外我也把 微信的 serviceimpl 不在做爲靜態的方法了,這樣每次進入都從新實例化一下,防止引發併發問題。我是參考了以下的博文,受到了啓發。感謝網友的知識共享。css

Spring @SessionAttributes @ModelAttributejava

package me.chanjar.weixin.cp.controller;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import me.chanjar.weixin.common.bean.result.WxCpBatchUpdateUserResult;
import me.chanjar.weixin.common.bean.result.callback;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.api.Writelog;
import me.chanjar.weixin.cp.api.WxCpInMemoryConfigStorage;
import me.chanjar.weixin.cp.api.WxCpServiceImpl;
import me.chanjar.weixin.cp.po.UserInfo;
import me.chanjar.weixin.cp.service.UserInfoService;
import me.chanjar.weixin.cp.util.crypto.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
/**
 * 單純實現OAuth2驗證,不使用註解及攔截器
 * 
 * 
 * 
 */
@Controller 
@SessionAttributes("Userid")
public class SimpleOAuth2Controller {
	String accsstoken = "";
	public static WxCpInMemoryConfigStorage config;
	public WxCpServiceImpl wxserv;
	public static callback callback;
	public static WxCpBatchUpdateUserResult wxcpbur;
	static {
		/*** 實例化static類 ***/		
		config = new WxCpInMemoryConfigStorage();
		callback=new callback();
		wxcpbur=new WxCpBatchUpdateUserResult();
		callback.setUrl("");
		callback.setEncodingaeskey("");
		callback.setToken("");
		wxcpbur.setcallback(callback);
		config.setCorpId(""); // 設置微信企業號的appid
		config.setCorpSecret(""); // 設置微信企業號的app																								// corpSecret
		config.setAgentId("2"); // 設置微信企業號應用ID=2,工資查詢
		config.setToken(""); // 設置微信企業號應用的token
		config.setAesKey(""); // 設置微信企業號應用的EncodingAESKey
	
	}
	
	/**
	 * 拼接網頁受權連接 此處步驟也能夠用頁面連接代替
	 * 
	 * @return
	 * @throws IOException
	 */
	@RequestMapping(value = "/oauth2wx.do", method = RequestMethod.GET)
	public String Oauth2API(HttpServletRequest request) throws IOException {
		// 獲取項目域名
		String reqUrl = "";
		Writelog.writetolog("得到項目域名:" + reqUrl);
		// 拼接微信回調地址
		String backUrl = "http://" + reqUrl + "/oauth2me.do";
		String redirect_uri = "";// 帶上oauth2me.do返回
		try {
			redirect_uri = java.net.URLEncoder.encode(backUrl, "utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String oauth2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
				+ "&redirect_uri="
				+ redirect_uri
				+ "&response_type=code&scope=snsapi_base&state=sunlight#wechat_redirect";
		Writelog.writetolog("返回oath2url:" + oauth2Url);
		return "redirect:" + oauth2Url;
	}

	/**
	 * 受權回調請求處理
	 * 
	 * @return
	 */
	@RequestMapping(value = { "/oauth2me.do" })
	
	public String oAuth2Url(@RequestParam String code, Model model) {
			//HttpSession session = request.getSession();
		try {
			String Userid = "";// 用於得到用戶的userid
			wxserv = new WxCpServiceImpl();
			wxserv.setWxCpConfigStorage(config);
			String userinfo[] = wxserv.oauth2getUserInfo(code);
			Userid = userinfo[0];// 得到userid
			Writelog.writetolog("得到usercode:" + code);
			Writelog.writetolog("得到userid" + Userid);
			model.addAttribute("Userid",Userid);

		} catch (WxErrorException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "/WEB-INF/user"; // 返回頁面
	}
	
   /*****
    * 
    * @param service
    */
	/***
	 * 業務邏輯
	 */
	@Autowired
	private UserInfoService service;
	public void setService(UserInfoService service) {
		this.service = service;
	}
}

一、@SessionAttributes,做用域在整個HTTP session 裏面-是 Session 級別的。

Using @SessionAttributes to store model attributes in the HTTP session between requests
The type-level @SessionAttributes annotation declares session attributes used by a specific
handler. This will typically list the names of model attributes or types of model attributes which should
be transparently stored in the session or some conversational storage, serving as form-backing beans
between subsequent requests.
The following code snippet shows the usage of this annotation, specifying the model attribute name:

web

@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet") //必須在class 外面申明
public class EditPetForm {
// ...
}

此外,@SessionAttributes 還能夠經過屬性類型指定要 session 化的 ModelMap 屬性,如 @SessionAttributes(types = User.class),固然也能夠指定多個類,如 @SessionAttributes(types = {User.class,Dept.class}),還能夠聯合使用屬性名和屬性類型指定:@SessionAttributes(types = {User.class,Dept.class},value={「attr1」,」attr2」})。經過value來指定多個屬性的名稱。spring

二、@ModelAttribute 屬性-是在 request 級別的。

2.1 Using @ModelAttribute on a method-在方法mapping 以前執行。

The @ModelAttribute annotation can be used on methods or on method arguments. This section
explains its usage on methods while the next section explains its usage on method arguments.
An @ModelAttribute on a method indicates the purpose of that method is to add one or more model
attributes. Such methods support the same argument types as @RequestMapping methods but cannot
be mapped directly to requests. Instead @ModelAttribute methods in a controller are invoked before
@RequestMapping methods, within the same controller.
A couple of examples:

api

// Add one attribute
// The return value of the method is added to the model under the name "account"
// You can customize the name via @ModelAttribute("myAccount")
@ModelAttribute
public Account addAccount(@RequestParam String number) {
    return accountManager.findAccount(number);
}
// Add multiple attributes
@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
    model.addAttribute(accountManager.findAccount(number));//經過model的addAttribute添加屬性。
    // add more ...
}

// 關於 @ModelAttribute在方法上面的做用-用於預先獲取一些數據。微信

@ModelAttribute methods are used to populate the model with commonly needed attributes for example to fill a drop-down with states or with pet types, or to retrieve a command object like Account in order to use it to represent the data on an HTML form. The latter case is further discussed in the next section.session

Note the two styles of @ModelAttribute methods. In the first, the method adds an attribute implicitly by returning it. In the second, the method accepts a Model and adds any number of model attributes to it. You can choose between the two styles depending on your needs.併發

A controller can have any number of @ModelAttribute methods. All such methods are invoked before @RequestMapping methods of the same controller.app

@ModelAttribute methods can also be defined in an @ControllerAdvice-annotated class and such methods apply to many controllers. See the the section called 「Advising controllers with the @ControllerAdvice annotation」 section for more details.ui

[Tip]-小技巧,若是沒有屬性的名稱沒有顯示定義,那麼默認的顯示名爲 返回類型的首字母小寫。

What happens when a model attribute name is not explicitly specified? In such cases a default name is assigned to the model attribute based on its type. For example if the method returns an object of type Account, the default name used is "account". You can change that through the value of the @ModelAttribute annotation. If adding attributes directly to the Model, use the appropriate overloaded addAttribute(..) method - i.e., with or without an attribute name.

The @ModelAttribute annotation can be used on @RequestMapping methods as well. In that case the return value of the @RequestMapping method is interpreted as a model attribute rather than as a view name. The view name is derived from view name conventions instead much like for methods returning void — see Section 17.13.3, 「The View - RequestToViewNameTranslator」.

2.2 Using @ModelAttribute on a method argument-將 @ModelAttribute 使用在方法參數裏面。

As explained in the previous section @ModelAttribute can be used on methods or on method arguments. This section explains its usage on method arguments.

An @ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument's fields should be populated from all request parameters that have matching names. This is known as data binding in Spring MVC, a very useful mechanism that saves you from having to parse each form field individually.

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) { }// pet 屬性是如何實例化的呢,請看以下說明。

Given the above example where can the Pet instance come from? There are several options:

It may already be in the model due to use of @SessionAttributes — see the section called 「Using @SessionAttributes to store model attributes in the HTTP session between requests」.

It may already be in the model due to an @ModelAttribute method in the same controller — as explained in the previous section.

It may be retrieved based on a URI template variable and type converter (explained in more detail below).

It may be instantiated using its default constructor.

An @ModelAttribute method is a common way to to retrieve an attribute from the database, which may optionally be stored between requests through the use of @SessionAttributes. In some cases it may be convenient to retrieve the attribute by using an URI template variable and a type converter. Here is an example:

@RequestMapping(value="/accounts/{account}", method = RequestMethod.PUT)
public String save(@ModelAttribute("account") Account account) {
}

In this example the name of the model attribute (i.e. "account") matches the name of a URI template variable. If you register Converter<String, Account> that can turn the String account value into an Account instance, then the above example will work without the need for an @ModelAttribute method.

The next step is data binding. The WebDataBinder class matches request parameter names — including query string parameters and form fields — to model attribute fields by name. Matching fields are populated after type conversion (from String to the target field type) has been applied where necessary. Data binding and validation are covered in Chapter 7, Validation, Data Binding, and Type Conversion. Customizing the data binding process for a controller level is covered in the section called 「Customizing WebDataBinder initialization」.

As a result of data binding there may be errors such as missing required fields or type conversion errors. To check for such errors add a BindingResult argument immediately following the @ModelAttribute argument:

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}

With a BindingResult you can check if errors were found in which case it’s common to render the same form where the errors can be shown with the help of Spring’s <errors> form tag.

In addition to data binding you can also invoke validation using your own custom validator passing the same BindingResult that was used to record data binding errors. That allows for data binding and validation errors to be accumulated in one place and subsequently reported back to the user:

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
    new PetValidator().validate(pet, result);
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}

Or you can have validation invoked automatically by adding the JSR-303 @Valid annotation:

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}
相關文章
相關標籤/搜索