论坛首页 Java企业应用论坛

Spring MVC 3.x annotated controller的几点心得体会

浏览 58632 次
该帖已经被评为精华帖
作者 正文
   发表时间:2010-12-20  
itstarting 写道
unsid 写道

参数里增加了@ModelAttribute("customerCommand") CustomerCommand customerCommand 就正常显示了,我很纳闷我hello这个方法根本用不到CustomerCommand customerCommand难道必须要在这声明?


其实你的hello方法的执行终点是渲染hello.jsp,此时hello.jsp会试图在request获取modelAttribute,但如果你按原来的写法,显然没有名字为customerCommand的modelAttribute,所以会有绑定异常,而你加上就可以了。

另外,你也可以直接new一个然后put到request里去,也是OK的,此时方法上可以不要这个参数(@ModelAttribute("customerCommand") CustomerCommand customerCommand)了:
model.addAttribute("customerCommand",new CustomerCommand ());



BTW:也许显式的写@ModelAttribute也是一种好习惯,但我一般懒得写,放在方法上即可,此时Spring能处理好,即使你没put到request去:
	@RequestMapping(value="/hello",method = RequestMethod.GET)
	public String hello(CustomerCommand customerCommand,Model model) {
		model.addAttribute("hello","helloworld!");
		return "hello";
	}


奥,你要怎么说我就理解modelAttribute的出处了,原来是从request里取CustomerCommand对象
但是每次打开一个带form的页面时候,都要从上一个controller里写一个model.addAttribute("customerCommand",new CustomerCommand ());么?这多不优雅啊,至少controller中加入了和这个controller关系不大的代码,你一般是这么写么?还是有什么更好的写法?
0 请登录后投票
   发表时间:2010-12-20  
unsid 写道
itstarting 写道
unsid 写道

参数里增加了@ModelAttribute("customerCommand") CustomerCommand customerCommand 就正常显示了,我很纳闷我hello这个方法根本用不到CustomerCommand customerCommand难道必须要在这声明?


其实你的hello方法的执行终点是渲染hello.jsp,此时hello.jsp会试图在request获取modelAttribute,但如果你按原来的写法,显然没有名字为customerCommand的modelAttribute,所以会有绑定异常,而你加上就可以了。

另外,你也可以直接new一个然后put到request里去,也是OK的,此时方法上可以不要这个参数(@ModelAttribute("customerCommand") CustomerCommand customerCommand)了:
model.addAttribute("customerCommand",new CustomerCommand ());



BTW:也许显式的写@ModelAttribute也是一种好习惯,但我一般懒得写,放在方法上即可,此时Spring能处理好,即使你没put到request去:
	@RequestMapping(value="/hello",method = RequestMethod.GET)
	public String hello(CustomerCommand customerCommand,Model model) {
		model.addAttribute("hello","helloworld!");
		return "hello";
	}


奥,你要怎么说我就理解modelAttribute的出处了,原来是从request里取CustomerCommand对象
但是每次打开一个带form的页面时候,都要从上一个controller里写一个model.addAttribute("customerCommand",new CustomerCommand ());么?这多不优雅啊,至少controller中加入了和这个controller关系不大的代码,你一般是这么写么?还是有什么更好的写法?

new一个我是不会干的,多烦啊

我认为有两种办法可以值得一试:
1、在方法上简单加上这个参数;
public String hello(CustomerCommand customerCommand,Model model) {
...
}

2、写一个专门的方法来初始化并就绪一个新的bean,这个方法需要加上@ModelAttribute

我一般用第一种。
第二种不是很好——所有方法都要执行,代码虽然“优雅”点但效率不高


试想一下,你要导航到一个form了,一般而言重要初始化一些东西,那么直接拿到这个从方法参数来的东西加工就是了
0 请登录后投票
   发表时间:2010-12-25  
最近在考虑一个问题,就是话说springMVC支持rest风格的URI,这样非常方便
你是怎么规划URI的呢?我觉得web应用的页面无非三种列表页面,详细信息页面和录入信息窗口页面,那么如果是以书为例,rest风格API怎么规划合理:
1、图书列表 /project/booktype/3/booklist
2、图书详细信息/project/booktype/3/booklist/4
3、录入页面怎么描述?/project/newbook?
   如果录入页面分很多栏信息?/project/newbook/1?
   如果这些新西兰嵌入到一个父frame里怎么表示frame?/project/newbookframe?
4、试想如果一个网站能在“最新图书列表”,“图书分类检索”里都能查到同一本书,那么一本图书对应两个URI?

/project/newbook或者project/newbookframe这种风格的URI不觉得很不REST么?
0 请登录后投票
   发表时间:2011-01-19  
体验很不错,但是唯有测试有点牵强:

public class HotelsControllerTest {  
      
    private static HandlerMapping handlerMapping;  
    private static HandlerAdapter handlerAdapter;  
      
    private static MockServletContext msc;  
  
    @BeforeClass  
    public static void setUp() {  
        String[] configs = {  
                "file:src/main/resources/context-*.xml",  
                "file:src/main/webapp/WEB-INF/webapp-servlet.xml" };  
        XmlWebApplicationContext context = new XmlWebApplicationContext();    
        context.setConfigLocations(configs);    
        msc = new MockServletContext();    
        context.setServletContext(msc);    
        context.refresh();    
        msc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);  
        ApplicationContextManager manager = new ApplicationContextManager();  
        manager.setApplicationContext(context);       
        handlerMapping = (HandlerMapping) ApplicationContextManager.getContext().getBean(DefaultAnnotationHandlerMapping.class);  
        handlerAdapter = (HandlerAdapter) ApplicationContextManager.getContext().getBean(ApplicationContextManager.getContext().getBeanNamesForType(AnnotationMethodHandlerAdapter.class)[0]);        
    }  
...
}


这段代码没必要,分析原因:
1.WebApplicationContext本身继承自ApplicationContext, 所以,使用@ContextConfiguration(locations={"spring-*.xml"}完全可以用ApplicationContext加载所有类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-dao.xml", "classpath:spring-service.xml", "classpath:spring-web.xml"}, inheritLocations = true)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class UserControllerTest {
	
    private static HandlerMapping handlerMapping;  
    private static HandlerAdapter handlerAdapter;
	
    @Before
    public void setUp() {
        handlerMapping  =   ApplicationContextHook.applicationContext.getBean(DefaultAnnotationHandlerMapping.class);
        handlerAdapter  = ApplicationContextHook.applicationContext.getBean(AnnotationMethodHandlerAdapter.class);
	}
...
}


hook spring的application即可
0 请登录后投票
   发表时间:2011-01-26  
请问搂主..
这个spring的验证说是要jsr-303规范..
就是不在spring的范畴里面..
我怎么打不出@valid注解.myeclipse没有提示..
我换了1.6的jdk还是编译错误.
0 请登录后投票
   发表时间:2011-01-26  
fq_jeid 写道
请问搂主..
这个spring的验证说是要jsr-303规范..
就是不在spring的范畴里面..
我怎么打不出@valid注解.myeclipse没有提示..
我换了1.6的jdk还是编译错误.



这个需要更多的依赖,一个是api另一个是实现,目前比较推荐的实现来自于hibernate。
比如:
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.0.0.GA</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.0.2.GA</version>
		</dependency>
0 请登录后投票
   发表时间:2011-01-27  
itstarting 写道
fq_jeid 写道
请问搂主..
这个spring的验证说是要jsr-303规范..
就是不在spring的范畴里面..
我怎么打不出@valid注解.myeclipse没有提示..
我换了1.6的jdk还是编译错误.



这个需要更多的依赖,一个是api另一个是实现,目前比较推荐的实现来自于hibernate。
比如:
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.0.0.GA</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.0.2.GA</version>
		</dependency>


项目中也用上JSR-303,做验证挺方便的,给个简单例子吧

<!-- 开启MVC注解 -->
<mvc:annotation-driven />


Bean代码:
public class User {

	private int id;

	@NotBlank(message = "用户名不能为空")
	@Size(min = 4, max = 16, message = "用户名长度必须为{min} ~ {max} 位")
	private String username;

	@NotBlank(message = "密码不能为空")
	@Size(min = 6, max = 20, message = "密码度必须为{min} ~ {max} 位")
	private String password;

	// 省略setter,getter
}



Controller代码:
@Controller
@RequestMapping("/user/*")
public class UserControler {

	@Resource
	private UserManager userManager;

	@RequestMapping(value = "save.do", method = RequestMethod.POST)
	public String save(@Valid User user, BindingResult result) {
		if (result.hasErrors()) {
			// 验证到错误时
			return "user/input";
		}
		userManager.save(user);
		return "user/success";
	}
}


当然,页面上也要对应有,不过也可以用上form标签来绑定
<input type="text" name="username" />
<input type="password" name="password" />


0 请登录后投票
   发表时间:2011-01-28  
kongruxi 写道


项目中也用上JSR-303,做验证挺方便的,给个简单例子吧

<!-- 开启MVC注解 -->
<mvc:annotation-driven />


Bean代码:
public class User {

	private int id;

	@NotBlank(message = "用户名不能为空")
	@Size(min = 4, max = 16, message = "用户名长度必须为{min} ~ {max} 位")
	private String username;

	@NotBlank(message = "密码不能为空")
	@Size(min = 6, max = 20, message = "密码度必须为{min} ~ {max} 位")
	private String password;

	// 省略setter,getter
}



Controller代码:
@Controller
@RequestMapping("/user/*")
public class UserControler {

	@Resource
	private UserManager userManager;

	@RequestMapping(value = "save.do", method = RequestMethod.POST)
	public String save(@Valid User user, BindingResult result) {
		if (result.hasErrors()) {
			// 验证到错误时
			return "user/input";
		}
		userManager.save(user);
		return "user/success";
	}
}


当然,页面上也要对应有,不过也可以用上form标签来绑定
<input type="text" name="username" />
<input type="password" name="password" />





我是担心验证的地方太多,逻辑看起来不方便(总是感觉不太完整),毕竟除了简单的表单验证之外,还有更为复杂的业务逻辑校验,所以我们为了统一,全部废掉JSR-303的做法,反而用了最原始的做法,即编写一套简单的验证工具,基于此工具编码验证。
0 请登录后投票
   发表时间:2011-01-28  
不知spring mvc今后是否会取代struts 呵呵
0 请登录后投票
   发表时间:2011-01-28  
其实我觉得原来的SpringMVC在validation这一块已经做得很不错了:
一般的输入合法性验证靠集成Commons-Validator框架,规则写在配置文件里,而且可以实现服务端客户端双重验证,灵活、集中、便于维护;
对于复杂的纯服务端验证,比如校验email是否已经存在,可以用SpringMVC自己的Validator框架,验证逻辑封装在Validator然后注入SimpleFormController,验证逻辑不会和业务逻辑混在一起,也很优雅。
而且上述两种验证可以同时使用,而且可以做到验证失败后,表单回填和错误信息的显示,集成的天衣无缝。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics