Spring框架已经出现了很多年,也是现在最流行的、使用范围最广的一种开发框架。Spring的也出现了很多种,我们熟悉的有Spring和Spring mvc 等。Spring框架也可以配合其他框架共同完成整个项目的开发,比如struts、hibernate、mybatis等等。在使用这些框架时,难免会配置一些繁琐的xml和property文件。这样在开发和维护过程中非常麻烦,一不小心少配置一步就会导致程序起不来,还找不到原因。为了简化配置,避免产生以上的问题,Spring boot出现了,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,使得Spring boot 程序能够快速构成开发框架,快速开发
如果只是使用@RestController注解Controller,则Controller中的方法无法返回html页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是return 里的内容。例如:本来应该到success.jsp页面的,则其显示success.
如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。
如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。
@Service+@Controller搭配使用
@Service 常用来标注一个业务模块,该模块以单件形式存在。
@Controller MVC里的控制器。
常用的一个实践是:rest请求在Controller里进行,具体业务则在service里实现,Controller负责将rest请求分发到service接口。下面是一个例子:
@Controller
@Path("/lee/v1/secu/auth")
public class RestAuthService extends AbstractROAService
{
...
@Autowired
private SecurityModuleItf smi_;
@GET
public String doGet(@QueryParam("oper") String oper, @QueryParam("roleNames") String roleNames, @QueryParam("roleIds") String roleIds)
{
try
{
if(!Strings.isNullOrEmpty(roleNames))
{
List<String> roleNameLst = Util.fromJson(roleNames, List.class);
return Util.genResponseJson(smi_.authByRoleNames(oper, roleNameLst), null, null) ;
}
...
}
catch(Exception e)
{
...
}
}
}
public interface SecurityModuleItf
{
...
boolean authByRoleNames(String oper, List<String> roleNames);
}
@Service
public class SecurityModule implements SecurityModuleItf
{
..
@RequestMapping注解
参数如下:
value: 指定请求的实际url地址, 比如 /action/info之类。
method: 指定请求的method类型, GET、POST、PUT、DELETE等
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
params: 指定request中必须包含某些参数值时,才让该方法处理
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求
一个样例:
@RequestMapping(value = "/test", method = RequestMethod.GET, headers="Referer=http://xxx.com/")
public void testHeaders(@PathVariable String ownerId, @PathVariable String petId) {
// implementation omitted
}
注意:也可以用GetMapping等简化的注解。
init和fini注解
init:@PostConstruct
fini:@PreDestroy
参数和成员注解
@PathVariable
@PathVaribale 获取url路径中的参数,例如获取
http://localhost:8080/hello/{id}
中的id,可以这样写:
@RequestMapping(value="/hello/{id}",method= RequestMethod.GET)
public String sayHello(@PathVariable("id") Integer id){
return "id:"+id;
}
1
2
3
4
5
@RequestParam
@RequestParam 获取url请求参数的值,例如获取
localhost:8080/hello?id=98
中的id值,可以这样写:
@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(@RequestParam("id") Integer id){
return "id:"+id;
}
1
2
3
4
注意:url里数组的写法:
/lee/comp_mgmt/v1/lib_desc?lib=x1&lib=x2
1
亦即:同名的key构成一个数组。
代码里这样写:
@GetMapping(value="/lib_desc")
public String showLibs(@RequestParam("lib") List<String> libNames) {
Map<String,String> res = compMgmtService.showLibs(libNames);
return SeDeUtil_Java.toJson(res);
}
1
2
3
4
5
@RequestBody
获得消息体中的json对象。下面例子使用@RequestBody从消息体中分离出SaleInput对象列表:
@PostMapping(value="/send_evt")
public String sendEvent(HttpServletRequest request, @RequestBody List<SaleInput> objs)
{
for (SaleInput o: objs)
{
evtFrmSvc.acceptEvent(o);
}
return "ok";
}
@Value注解
有$和#两种注解方式,$主要是配置文件里值的获取,格式为:
${ property : default_value }
1
#是bean属性的获取,格式为:
#{ obj.property }
1
如要在未给值时设定默认值,可以这样写:
#{ obj.property ?: default_value }
#{ obj.property ? obj.property : default_value }
1
2
上述两种写法的效果是一样的。
需要注意的是,如果是获取一个方法的值时,需要在前面增加@,比如
#{ @obj.getProperty() }
1
覆盖框架的spring bean定义
要覆盖的bean:
@Slf4j
public class HackDataSourceAliasMapper extends DataSourceAliasMapper {
public void init() {
try {
log.info("HackDataSourceAliasMapper.init()");
super.init();
}
catch (Exception e) {
log.warn("perish DataSourceAliasMapper failure");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
实现BeanDefinitionRegistryPostProcessor接口,把老的bean移除,替换成新的bean:
@Component
@Slf4j
public class MyBeanRegPostProc implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
String beanName = "dataSourceAliasMapper";
log.info("begin to hack bean:{} success", beanName);
beanDefinitionRegistry.removeBeanDefinition(beanName);
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(HackDataSourceAliasMapper.class);
beanDefinitionBuilder.setInitMethodName("init");
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
log.info("hack bean:{} success", beanName);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
log.info("postProcessBeanFactory: empty");
}
}
1
spring bean后处理的顺序
BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法先于
BeanDefinitionRegistryPostProcessor接口的postProcessBeanFactory方法先于
BeanFactoryPostProcessor接口的postProcessBeanFactory方法
1
2
3
与BeanDefinitionRegistryPostProcessor不同,BeanFactoryPostProcessor甚至可以修改bean实例!
调整bean的加载顺序
使用@DependsOnDatabaseInitialization可在dataSource初始化后立刻做一些事情(springboot2.5引入):
某些众所周知类型的bean(如JdbcOperations)将被排序,以便在数据库初始化之后对它们进行初始化。如果有一个直接使用DataSource的bean,请使用@DependsOnDatabaseInitialization注释它的类或@Bean方法,以确保它也在数据库初始化之后被初始化。
1
其它情况,若想调整两个bean间的关系,可用@DependsOn;当然,用autowired依赖也是可以的,且更自然。
————————————————
版权声明:本文为CSDN博主「天下无敌笨笨熊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tlxamulet/article/details/129458865