@Controller
注解一个类表示控制器,Spring MVC会自动扫描标注了这个注解的类。
@Controller
@RequestMapping("goods")
public class GoodsController extends BaseController{
}
@Service
将自动注册到Spring容器,加在业务层,一般对于接口和实现。
@Qualifier
如果一个接口有多个实现,那么注入时候加上唯一标示
同时有下述两个实现类 EmployeeServiceImpl和EmployeeServiceImpl1:
@Service("service")
public class EmployeeServiceImpl implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}
@Service("service1")
public class EmployeeServiceImpl1 implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}
调用的时候必须指定一个。
@Controller
@RequestMapping("/emplayee.do")
public class EmployeeInfoControl {
@Autowired
@Qualifier("service")
EmployeeService employeeService;
@RequestMapping(params = "method=showEmplayeeInfo")
public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) {
#略
}
}
@Autowried
它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。通过 @Autowired的使用来消除 set ,get方法默认是按照类型进行装配注入,默认情况下,它要求依赖对象必须存在,如果允许 null 值,可以设置它 required 为false。
如果我们想要按名称进行装配的话,可以添加一个 @Qualifier 注解解决。
/**
* 商品规格业务数据库操作类
*/
@Autowired
private GoodsSpecificBlo goodsSpecificBlo;
/**
* 商品业务数据库操作类
*/
@Autowired
private GoodsBlo goodsBlo;
/**
* 商品快照数据库操作类
*/
@Autowired
private GoodsSnapshotBlo goodsSnapshotBlo;
@RequestMapping
请求路径映射,可以标注类,也可以是方法,可以指定请求类型,默认不指定为全部接收。
指定方法
@RequestMapping(value="/new", method = RequestMethod.GET)
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
@Controller
@RequestMapping("goods")
public class GoodsController extends BaseController{
/**
* GoodsService业务操作Service
*/
@Autowired
private GoodsService goodsService;
/**
* 评价业务操作Service
*/
@Autowired
private EvaluationService evaluationService;
/**
*
* 模块访问方法:商品一览界面<br/>
* @param request http请求实例
* @return 返回页面名称
* @throws Exception
*/
@RequestMapping(value = "/list.htm")
public String GoodsList(HttpServletRequest request, GoodsVO goods) throws Exception {
// doSearch实现初期进入一览画面,不做查询
String doSearch = request.getParameter("doSearch");
if (StringUtil.isNotBlank(doSearch)) {
goodsService.search(request, goods);
}
// 跳转页面
return "goods/goods_list";
}
}
@RequestParam
放在参数前,表示只能接收参数a=b格式的数据,@RequestParam是传递参数的. 用于将请求参数区数据映射到功能处理方法的参数上。
指定传入的参数名
public void getUser( @RequestParam(value="user") String userName, @RequestParam(value="pass") String userPassword,
HttpServletRequest request)
通过required=false or true ,指定该参数是否必须要传,如果为true,则该参数必须传;如果为false, 则可以不传,会默认赋值为null
如果用@RequestParam注解的参数是int基本类型,但是required=false,这时如果不传参数值会报错,因为不传值,会赋值为null给int.最好用包装类型。
public void getUser( @RequestParam(value="user",required = true) String userName,
@RequestParam(value="pass",required = false) String userPassword,)
如果不用@RequestParam注解,也可以获得参数,如果没有传该参数不会报错。
public void getUser( String userName, String userPassword)
@RequestBody
放在参数前,表示参数从request body中获取,而不是从地址栏获取,所以这肯定是接收一个POST请求的非a=b格式的数据,@RequestBody接收的是一个Json对象的字符串,而不是一个Json对象。
然而在ajax请求往往传的都是Json对象,后来发现用 JSON.stringify(data)的方式就能将对象变成字符串。同时ajax请求的时候也要指定dataType: "json",contentType:"application/json" 这样就可以轻易的将一个对象或者List传到Java端,使用@RequestBody即可绑定对象或者List.
<script type="text/javascript">
$(document).ready(function(){
var saveDataAry=[];
var data1={"userName":"test","address":"gz"};
var data2={"userName":"ququ","address":"gr"};
saveDataAry.push(data1);
saveDataAry.push(data2);
$.ajax({
type:"POST",
url:"user/saveUser",
dataType:"json",
contentType:"application/json",
data:JSON.stringify(saveData),
success:function(data){
}
});
});
</script>
@RequestMapping(value = "saveUser", method = {RequestMethod.POST }})
@ResponseBody
public void saveUser(@RequestBody List<User> users) {
// TODO
}
再看一个例子
$.ajax({
type: "post",
contentType:"application/json",
url: "repairs/saveDispatches",
data: JSON.stringify(dispatchesDTO),
success: function(data){
if(!data.success){
}else{
alertSuccess("派工成功");
}
})
@RequestMapping("/repairs/saveDispatches")
public void saveDispatches(@RequestBody DispatchesDTO dispatchesDTO,
HttpServletResponse response) throws IOException {
dispatchesService.saveDispatches(dispatchesDTO);
success(response);
}
@ResponseBody
直接往response中写内容而不经过视图解析器时可以使用@ResponseBody
放在方法上或者返回类型前,表示此方法返回的数据放在response body里面,而不是跳转页面。一般用于ajax请求,返回json数据。
/**
* 取得商品类型<br/>
* @param request 请求实例
* @return retMap
* @throws Exception
*/
@ResponseBody
@RequestMapping(value = "/getTypeList.htm")
public HashMap<String, Object> getCountyList(HttpServletRequest request) throws Exception {
HashMap<String, Object> retMap = new HashMap<String, Object>();
List<Goods> retVal = goodsService.getTypeList(request);
retMap.put("infoMsg", retVal);
return retMap;
}
@RestController
这个是Controller和ResponseBody的组合注解,表示@Controller标识的类里面的所有返回参数都放在response body里面。
@RestController =@Controller + @ResponseBody controller中方法都自带@ResponseBody
源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
}
@PathVariable
路径绑定变量,用于绑定restful路径上的变量。
在spring MVC中,两者的作用都是将request里的参数的值绑定到contorl里的方法参数里的,区别在于,URL写法不同。
使用@RequestParam时,URL是这样的:http://host:port/path?参数名=参数值
使用@PathVariable时,URL是这样的:http://host:port/path/参数值
@RequestMapping(value="/user",method = RequestMethod.GET)
public @ResponseBody
User printUser(@RequestParam(value = "id", required = false, defaultValue = "0")
int id) {
User user = new User();
user = userService.getUserById(id);
return user;
}
@RequestMapping(value="/user/{id:\\d+}",method = RequestMethod.GET)
public @ResponseBody
User printUser2(@PathVariable int id) {
User user = new User();
user = userService.getUserById(id);
return user;
}
访问路径分别是http://localhost:8080/user?id=1 和 http://localhost:8080/user/1
PathVariable的请求路径可以被猜到。
@Transactional
注解式事务
/**
* 商品编辑:根据GoodsVO的isAdd字段判断更新商品记录或新增商品记录
* @param GoodsVO 经销商信息
* @param isAdd 0 编辑,1 追加
* @return Integer 更新结果条目数
* @throws Exception
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public int editGoods(HttpServletRequest request, GoodsVO goods, String isAdd) throws Exception {
}
事物传播行为介绍:
@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
事物超时设置:
@Transactional(timeout=30) //默认是30秒
事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化
MYSQL: 默认为REPEATABLE_READ级别SQLSERVER: 默认为READ_COMMITTED
注意:转载
1. 不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
2.不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。
3.使用了@Transactional的方法,对同一个类里面的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。(经常在这里出错)
4.使用了@Transactional的方法,只能是public,@Transactional注解的方法都是被外部其他类调用才有效,故只能是public。道理和上面的有关联。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但事务无效。
5.经过在ICORE-CLAIM中测试,效果如下:
A.抛出受查异常XXXException,事务会回滚。
B.抛出运行时异常NullPointerException,事务会回滚。
C.Quartz中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
D.异步任务中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
E.在action中加上@Transactional,不会回滚。切记不要在action中加上事务。
F.在service中加上@Transactional,如果是action直接调该方法,会回滚,如果是间接调,不会回滚。(即上文3提到的)
G.在service中的private加上@Transactional,事务不会回滚。
H.spring的事务在抛异常的时候会回滚,如果是catch捕获了,事务无效。
注解中常用参数说明:
参数名称 | 功能描述 |
readOnly | 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true) |
rollbackFor | 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如: 指定单一异常类:@Transactional(rollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class}) |
rollbackForClassName | 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如: 指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException") 指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"}) |
noRollbackFor | 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如: 指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class}) |
noRollbackForClassName | 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如: 指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException") 指定多个异常类名称: @Transactional(noRollbackForClassName={"RuntimeException","Exception"}) |
propagation | 该属性用于设置事务的传播行为,具体取值可参考表6-7。 例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) |
isolation | 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置 |
timeout | 该属性用于设置事务的超时秒数,默认值为-1表示永不超时 |
@RequestHeader
放在方法参数前,用来获取request header中的参数值。
/@RequestHeader:获取浏览器头信息:限制请求头中必须有User-Agent
//User-Agent:封装了浏览器的信息
//helloMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
@RequestMapping("show22")
public String show22(@RequestHeader("User-Agent")String browser){
System.out.println("hello"+browser);
return "/index.jsp";
}
@CookieValue
可让处理方法入参绑定某个 Cookie 值 Cookie 存在时才能取到
@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
@RequestMapping("/testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID")String sessionId){
System.out.println("testCookieValue: "+sessionId);
return "success";
}
}