一、写法一:
@RestController
@RequestMapping("/advertise")
public class AdvertiseController {
@CrossOrigin
@RequestMapping(value = "/add/{id}", method = RequestMethod.POST)
public JSONObject addAdvertise(@RequestBody JSONObject params, @Context HttpServletRequest request, @PathVariable("id") String id) {
1.@PathVariable:
通过@PathVariable可以将URL中占位符参数绑定到控制器处理方法的入参中:URL中的{xxx}占位符可以通过@PathVariable(“xxx”)绑定到操作方法的入参中。
2.@RequestBody:
将请求体中的整体数据转化为对象,GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。
3.@Context:
不太了解这个注解,但是我发现把这个注解去掉也不影响啥。
@RestController
public class HuiController {
@RequestMapping(value="huitest")
public String hui(@RequestBody JSONObject params, HttpServletRequest request) {
String qiang = request.getParameter("hehe");
String xiao = params.getString("qiang");
return qiang + "<-->" + xiao;
}
}
也可以用这个curl命令测试:
curl http://localhost:8080/huitest -X POST -d '{"qiang":"qie"}' --header "Content-Type: application/json"
4.@CrossOrigin:
是用来处理跨域请求的注解
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
所谓同源是指,域名,协议,端口均相同,不明白没关系,举个栗子:
http://www.123.com/index.html 调用 http://www.123.com/server.PHP (非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
当域名www.abc.com下的js代码去访问www.def.com域名下的资源,就会受到限制。
@CrossOrigin可以处理跨域请求,让你能访问不是一个域的文件。
5.@RequestMapping:
配置url映射,此注解即可以作用在控制器的某个方法上,也可以作用在此控制器类上。
当控制器在类级别上添加@RequestMapping注解时,这个注解会应用到控制器的所有处理器方法上。处理器方法上的@RequestMapping注解会对类级别上的@RequestMapping的声明进行补充。
例子一:@RequestMapping仅作用在处理器方法上
@RestController
public class HelloController {
@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){
return "hello";
}
}
以上代码sayHello所响应的url=localhost:8080/hello。
例子二:@RequestMapping仅作用在类级别上
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method= RequestMethod.GET)
public String sayHello(){
return "hello";
}
}
以上代码sayHello所响应的url=localhost:8080/hello,效果与例子一一样,没有改变任何功能。
例子三:@RequestMapping作用在类级别和处理器方法上
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(value="/sayHello",method= RequestMethod.GET)
public String sayHello(){
return "hello";
}
@RequestMapping(value="/sayHi",method= RequestMethod.GET)
public String sayHi(){
return "hi";
}
}
这样,以上代码中的sayHello所响应的url=localhost:8080/hello/sayHello。
sayHi所响应的url=localhost:8080/hello/sayHi。
@RequestMapping 和 @GetMapping @PostMapping 区别:
@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。
@PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。
如果@RequestMapping不指定请求方式则两种请求方式都可以。
@RestController
public class HuiController {
@RequestMapping("huitest")
// @PostMapping("huitest") 和 @RequestMapping(value="huitest",method = RequestMethod.POST)等效
// @GetMapping(value="huitest") 和 @RequestMapping(value="huitest",method = RequestMethod.GET)等效
public String hui(HttpServletRequest request) {
String hui = request.getParameter("hehe");
return hui;
}
}
用浏览器直接访问其实是GET请求
6.@RestController:
在spring4.0之后,引入了@RestController这个注解。这个注解相当于把@ResponseBody + @Controller合在一起。
我们先来看一下@RestController的源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
String value() default "";
}
前端在通过表单提交和a标签请求后端的时候只需要注解@Controller即可,但是在通过Ajax请求后端的时候,还需要增加一个@ResponseBody注解,但是在spring4.0之后,无论是表单还是a标签还是Ajax请求后端,都只要@RestController一个注解即可。
@ResponseBody能将对象自动转换为json字符串,所以以往在Ajax返回时直接返回一个对象就行,而在表单和a标签请求是返回需要调用JSON.toJSONString(object)这个方法将对象转换为json字符串。
在spring4.0后,所有请求在@RestController之下,直接返回对象即可,再也不需要转换为json字符串了。
@RestController
public class HelloController {
@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){
return "hello";
}
}
与下面的代码作用一样
@Controller
@ResponseBody
public class HelloController {
@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){
return "hello";
}
}
使用了@RestController之后,所有返回的数据他都会把你解析为json字符串,所以如果是前后台不分开式开发(即返回的是跳转页面名字)时,不能使用@RestContoller,不然只会在原来页面中显式你要跳转页面的名字!
可参考:http://www.ityouknow.com/springboot/2016/02/03/spring-boot-web.html
注意:@Contoller注解在springboot1.5以前的版本中在maven配置spring-boot-starter-web(@Contoller引入的包是org.springframework.stereotype.Controller)中有,而1.5及以后则没有了。
二、写法二(其实就是Jersey写Restful接口):
@Path("/admin")
@Component
public class ManagementResource {
@POST
@Path("/login")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@CrossOrigin
public Response login(JSONObject params, @Context HttpServletRequest request) {
1.@Component:
使用@Component是让该类能够在其他地方被依赖使用,即可以直接在其他地方使用@Autowired来创建其实例对象。
强力推荐:Spring注解详解
2.@Produces:
@Produces注释用来指定将要返回给client端的数据标识类型(MIME)。@Produces可以作为class注释,也可以作为方法注释,方法的@Produces注释将会覆盖class的注释。
a.返回给client字符串类型(text/plain)
@Produces(MediaType.TEXT_PLAIN)
b.返回给client为json类型(application/json)
@Produces(MediaType.APPLICATION_JSON)
3.@Consumes:
@Consumes与@Produces相反,用来指定可以接受client发送过来的MIME类型,同样可以用于class或者method,也可以指定多个MIME类型,一般用于@PUT,@POST
a.接受client参数为字符串类型
@Consumes(MediaType.TEXT_PLAIN)
b.接受clent参数为json类型
@Consumes(MediaType.APPLICATION_JSON)
三、其他常用注解:
1.@Bean:
放在方法上,用@Bean标注方法等价于XML中配置bean,这个方法一般返回一个实体对象,告诉spring这里产生一个对象,然后这个对象会交给Spring管理。产生这个对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的容器中。
2.@Configuration:
标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到srping容器中,并且实例名就是方法名。(其实就是靠@Component注解),源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}
3.@Resource:
是按照名称来注入的,当找不到与名称匹配的bean才会按照类型来注入。其实我们平时用的@Resource都是用了他的默认的方式,即都不指定名字和类型。spring通过反射机制使用byName方法自动注入。
@Resource(type = ShiroService.class, name = "shiroService")
private ShiroService shiroService;
@Resource 的装配顺序:
- 如果同时指定了 name 属性和 type 属性,那么 Spring 将从容器中找唯一匹配的 bean 进行装配,找不到则抛出异常
- 如果指定了 name 属性值,则从容器中查找名称匹配的 bean 进行装配,找不到则抛出异常
- 如果指定了 type 属性值,则从容器中查找类型匹配的唯一的 bean 进行装配,找不到或者找到多个都会抛出异常
- 如果都不指定,则会自动按照 byName 方式进行装配(我们一般都用的是这个。。。)
4.@Autowried:
默认是按照类型进行装配注入,如果允许 null 值,可以设置它 required 为false。即:当不能确定 Spring 容器中一定拥有某个类的 Bean 时,可以在需要自动注入该类 Bean 的地方可以使用 @Autowired(required = false) ,这等于告诉 Spring:在找不到匹配 Bean 时也不报错。
@Autowired(required = false)
private ShiroService shiroService;
5.@Qualifier:
@Autowired是根据类型进行自动装配的。如果当spring上下文中存在不止一个A类型的bean时,就会抛出BeanCreationException异常;如果Spring上下文中不存在A类型的bean,而且我们又使用A类型,也会抛出BeanCreationException异常。针对存在多个A类型的Bean,我们可以联合使用@Qualifier和@Autowired来解决这些问题。
@Autowried
@Qualifier("adminDAO")
private AdminDAO adminDAO;
6.@SpringBootApplication:
这个注解就是集成了:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这三个注解。其中@SpringBootConfiguration:表示这个类为配置类;@EnableAutoConfiguration:表示开启自动配置,我们平时所说springboot无配置就是这个参数起的作用,他读取了springboot默认的配置;@ComponentScan:表示自动扫描,这个扫描默认只能扫同一级的目录。
7.@Async与@EnableAsync:
其中@Async表示这个方法为异步方法;@EnableAsync这个注解需要加在启动类上,表示支持异步操作;如果不加,则@Async将不起作用。
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncservice;
@RequestMapping("/asyncTest.do")
public String asyncTest() {
System.out.println("############asyncTest############");
System.out.println("############a############");
asyncservice.test();
System.out.println("############b############");
return "success";
}
@RequestMapping("/asyncTest2.do")
public String asyncTest2() {
System.out.println("############asyncTest2############");
System.out.println("############a############");
asyncservice.test2();
System.out.println("############b############");
return "success";
}
@RequestMapping("/asyncTest3.do")
public String asyncTest3() {
System.out.println("############asyncTest3############");
System.out.println("############a############");
asyncservice.test3();
System.out.println("############b############");
return "success";
}
}
@Service
public class AsyncService {
public void test() {
System.out.println("############c############");
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
System.out.println("############d############");
}
@Async
public void test2() {
System.out.println("############c############");
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
System.out.println("############d############");
}
/**
* @Async就相当于另起一个线程
*/
public void test3() {
new Thread() {
@Override
public void run() {
System.out.println("############c############");
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
System.out.println("############d############");
}
}.start();
}
}
实验结果是: asyncTest.do输出为: acdb; asyncTest2.do输出为: abcd; asyncTest3.do输出为: abcd;
所以简单来说:@Async就相当于另起一个线程。