以SpringBoot3或者Spring6为基准
依赖注入
Bean注入
- 可以依靠@Autowired、@Resource两个注解用于Bean注入
@Autowired:Spring的注解;按类型来查找相应的实例进行注入,若还用了@Qualifier则按指定的实例名查找实例;有name、type等属性
按照类型自动装配
@Component public class UserBean { @Autowired private RoleBean role; public String toString(){ return "属性role为:"+this.role; } }
@Resource:JDK1.6开始提供的注解;按实例名字查找实例
@Component
public class UserBean {
@Resource(name="role1")
private RoleBean role;
public String toString(){
return "属性role为:"+this.role;
}
}
2、配置文件中的参数注入到java变量:@Value
@Component
public class UserBean {
@Value("${abc.name}")
private String name;
Bean定义
根据被Spring容器发现的方式可分为两类
自动扫描:@Component,注意@Controller、@Service、@Repository三者与@Component等效,只不过在语义上更明确。@Component用在类上,声明此类是个受管Bean,会被SpringComponentScan扫描并由Spring容器自动创建实例并注册
受管bean
@Component public class RoleBean { }
配置类
@Configuration @ComponentScan //默认自动扫描所在的包及其子包中所有类,如果添加了 @Component注解 则是受管bean public class MyConfig { }
手动配置:@Configuration+@Bean前者用在类上、后者用在@Configuration修饰的类内的方法上,效果相当于xml中的beans与bean的关系;实例需要用户在@Bean修饰的方法中手动创建返回,Spring容器通过@Configuration扫描并注册其所修饰的类内的Bean
受管bean的类定义
public class RoleBean { }
配置类
@Configuration //用于声明当前类是一个配置类,一个应用中可以多个配置 public class MyConfig { @Bean //当前方法的返回值就是一个受管bean public RoleBean role(){ return new RoleBean(); } }
另外还有@Scope、@RequestMapping(@GetMapping、@PostMapping…)、@ResponseBody等
Component注解
@Component是所有受Spring 管理组件的通用形式,@Component注解可以放在类的头上,在具体的应用开发中@Component不推荐使用
@Controller对应表现层的Bean,也就是Action,使用@Controller注解标识UserAction之后,就表示要把UserAction交给Spring容器管理,在Spring容器中会存在一个名为userAction的action,这个名字是根据UserAction类名来取的
注意:如果@Controller不指定其value,则默认的bean名字为这个类的类名首字母小写,如果指定value,则使用value作为bean的名字
@Service对应的是业务层Bean
@Service
public class MyServImpl{}
@Repository对应数据访问层Bean
@Repository
public class MyDao{}
@scope注解
@Scope注解标记在类和方法,标记Spring受管Bean作用域:singleton、prototype、request、session、application【不是老版本的global session】,允许用户自定义
singleton单例,无论getBean多少次得到的都是同一个实例。默认值
- applicationContext立即加载
- beanFactory延迟加载
- 所有的非单例bean则都采用延迟加载
@Component
@Scope("singleton")
public class UserBean
调用处两次获取对象,但是对象所属类的构造器只执行一次
UserBean user=ac.getBean(UserBean.class); //按照类型获取对象 UserBean user2=ac.getBean("userBean",UserBean.class); //按照名称获取对象 System.out.println(user==user2); //判断两次获取的对象是否为同一个对象
prototype:每次getBean都创建一个新的实例。类似于new操作
@Scope(“prototype”)表示将组件范围声明为原型,可以利用容器的scope="prototype"来保证每一个请求有一个单独的实例对象来处理,典型应用就是避免struts2中Action的线程安全问题spring默认scope是单例模式singleton,这样只会创建一个组件对象,每次访问都是同一组件对象,数据不安全,在struts2整合Spring时,就是要求每次次访问都对应不同的控制器,scope=prototype可以保证当有请求的时候都创建一个控制器对象
针对web应用还有3个范围,如果不是web应用则这三个范围无效
- request:每个http请求创建一个实例,该实例仅在该请求内有效且该请求过程中用同一个实例,不同request创建的实例互不干扰;实例随请求结束而销毁
- session:每当创建一个会话时创建一个实例,实例随着会话的结束而销毁
- application:不是Portlet API中对应的那个global session。在一个ServletContext生命周期内公用一个实例。注不是ApplicationContext,一个ServletContext可能包含多个ApplicationContext
SpringMVC中的方法定义
接收请求参数
- 使用HttpServletRequest获取,如request.getParameter(“name”)
@Controller
public class MyController{
@GetMapping("/demo")
public String demo(HttpServletRequest request){
String username=request.getParameter("username"); 会造成和运行环境耦合,如果需要还应该进行类型转换。
... ...
}
}
- 在方法声明参数,如@RequestParam(“pass”)String password,表单参数也可以用这种方式获取,Spring会自动将表单参数注入到方法参数,和表单的name属性保持一致。
参数名称和提交数据的名称一致,在request的paramete的请求参数名称一致
@GetMapping("/hello") public String sayHello(String username,Integer num){}
用于请求参数名称和方法参数名称不一致
@GetMapping("/hello") public String sayHello(@RequestParam("name") String username, @RequestParame("id") Long number){}
- 对于URL中的参数,还可以使用Map来接收;对于非url中的参数,可以用Map、POJO接收自动注入Bean属性
public String sayHello(User user,Errors error1,Role role,Errors errors2)
{}
向页面传参
使用HttpServletRequest和HttpSession,然后setAttribute(),就和Servlet中一样
public String sayHello(HttpServletRequest request,HttpSession session)
{}//session不会出现null
使用ModelAndView对象
ModelAndView mv=new ModelAndView();
mv.setViewName("hello"); //逻辑视图名
mv.addObject("user",new Date()); //类似于request.setAttribute("user",new
Date())
使用Model对象
public String sayHello(String username,Model model){
model.addObject("msg","传递的数据");
}
使用@ModelAttribute注解
@ModelAttribute
public Date now(){
return new Date(); }
@ModelAttribute注解可以用于方法参数或者方法上
- 定义在方法上用于表示当前类中的所有映射方法执行之前必须执行的方法,返回值将自动存储到model中
- 定义在方法的参数上用于表示接收数据之后再执行model.addAttribute
属性value等价于name,用于指定向model中存储数据时的key值
常见的场景:输入页面的原始数据准备,例如
@RequestMapping注解
@RequestMapping(@GetMapping、@PostMapping…)
@RequestMapping注解可以用于类上或者方法上
- 定义在类上用于指定当前类中所有方法的名空间
- 定义在方法上用于指定方法对应的URL地址
@Controller //声明当前类是控制器
@RequestMapping("/user")
public class UserController{
@RequestMapping("/login") 当前方法对应的URL路径为【类上的路径+方法上的路
径】,请求路径为/user/login
public String sayHello(String name,Model model){}
}
异常捕获处理
@ExceptionHandler捕获特定异常进行处理,仅对当前Controller有效
@Controller
public class HelloController {
@RequestMapping("/hello")
public String sayHello(String name) throws Exception{
if("yanjun".equals(name))
throw new Exception("名称不合法!"); //运行时和非运行时均可
return "show";
}
@ExceptionHandler(Throwable.class) 需要有参数表示处理异常的类型,否则不做任何处
理
public String handleError(Exception ex,Model model){//方法ex用于获取对应的
异常对象
ex.printStackTrace();
//针对不同异常有不同的处理方法
if(ex instanceof Exception) {
model.addAttribute("err", ex);
}
return "error";
}
}
@ControllerAdvice修饰类,捕获全局各个Controller抛出的异常或者定义全局相关的内容。ControllerAdvice注解只拦截Controller不会拦截Interceptor的异常
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(Throwable.class)
public String handleError(Exception ex, Model model){
System.out.println("xixixi");
ex.printStackTrace();
//针对不同异常有不同的处理方法
if(ex instanceof Exception) {
model.addAttribute("err", ex);
}
return "error";
}
}
值得注意的是只对Controller类中的handler抛出的异常有效,对其他的异常,如404、servlet的filter抛出的异常无效
非Controller的handler所抛异常
因为如果404则会自动跳转error,定义error对应的的页面则会跳转到error逻辑地址名对应的页面
web应用容器会在发生异常后将异常记录到request attribute中,并将当前请求forward到错误页面,默认是/error
记录到request的属性包括:
- jakarta.servlet.error.request_uri:String类型
- jakarta.servlet.error.exception:Throwable类型,如果是404则没有异常信息
- jakarta.servlet.error.message:String类型
- jakarta.servlet.error.status_code:Integer类型
在template下创建error文件夹,里面放404.html,就会跳转到404页面。原因springboot项目内置tomcat,而tomcat没有设置错误友好页面,而springboot得约定大于配置在于我们配置的时候只要按照创建工程的结构来创建,springboot会按照目录结构去加载,也就是在maven项目下,加载页面,默认得在resource目录下template下加载,而错误页面默认使用得下一级目录也就是error,页面名就是以状态码来命名,所以可以成功加载。
配置方式
@Component
public class MyErrorPage implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
/*1、按错误的类型显示错误的网页*/
/*错误类型为404,找不到网页的,默认显示404.html网页*/
ErrorPage e404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
/*错误类型为500,表示服务器响应错误,默认显示500.html网页*/
ErrorPage e500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,
"/500.html");
/*2、按具体某个异常显示错误的网页*/
/*当某个异常即可以根据错误类型显示错误网页,由可以根据某个具体的异常来显示错误网页时,优先根据具体的某个异常显示错误的网页*/
ErrorPage argsException = new ErrorPage(IllegalArgumentException.class,
"/args.html");
registry.addErrorPages(e404, e500);
}
}