Spring和MVC
SpringMVC
是Spring框架的明星产品,用来 接收浏览器发来的请求+并返回响应数据
遵循MVC思想: 主要是想要松耦合,实现代码间的高内聚, 提高代码的可维护性
M 是Model, 模型层, 用来封装数据
V 是View, 视图层, 用来展示数据
C 是Controller, 控制层 作用就是用来 接受请求和给出响应
一、工作原理(工作流程)
1, 前端控制器DispatcherServlet: 接受请求并分发请求 /dɪˈspætʃə(r)/ /ˈsɜːvlɪt/
2, 处理器映射器HandlerMapping: 根据请求,找到具体能处理请求的类名,方法名
3, 处理器适配器HandlerAdapter: 正式开始调用方法处理请求,并返回结果
4, 视图解析器ViewResolver: 把页面找到,把数据进行解析
5, 视图渲染View: 具体展示数据并返回给浏览器
二、实现前后端交互使用到的注解
1、@GetMapping @PostMapping @DeleteMapping @PutMapping
规定浏览器的不同访问方式
2、@RequestMapping
将请求 和 处理请求的 控制器方法 关联起来,建立映射关系。SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
@RequestMapping标识一个类:设置映射请求的请求路径的初始信息。
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息。
3、@ResponseBody
作用在方法上,将该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中。
4、@RequestBody
作用在形参列表上,用于将前台发送过来固定格式的数据【xml 格式或者 json等】封装为对应的 JavaBean 对象
5、@RestController
@RestController注解相当于@ResponseBody + @Controller合在一起的作用
6、get请求参数解析
(1)路径拼接形式
http://localhost:8080/car/insert?id=1&name=张三&age=18@GetMapping("/add")
public static String add(Integer id ,String color,Integer price){return "汽车的编号为:"+id+" "+"颜色为:"+color+"价格为:"+price;
}
注意事项:服务器端参数类型使用包装类型,默认为null,避免客户端传入数据不赋值报错。
(2)RESTFul风格
http://localhost:8325/api/BuildingMessageManagementController/id@GetMapping("/{id}")
public Result selectById(@PathVariable String id) {}
7、Post/Put 参数解析
(1)浏览器传来formdata形式的参数,直接使用对象接参。
(2)浏览器惨传来json形式参数,使用@RequestBody接参。
@PostMapping("/saveUser")
// RequestBody属性作用:body中对象为空,就不接收解析,避免报错
public String saveUser(@RequestBody(required = false) User user){userService.saveUser(user);return "用户入库成功!!!";
}
(3)@PathVariable RestFul风格传参
http://localhost:8008/api/findAllWorkRecord/pageNum/pageSize
@PostMapping({"/findAllWorkRecord", "/findAllWorkRecord/{pageNum}/{pageSize}"})
public Result findAllWorkRecord(@PathVariable(required = false) Integer pageNum, @PathVariable(required = false) Integer pageSize, @RequestBody(required = false) WorkRecord model)
访问路径为数组形式,参数携带在路径上;
路径上的参数使用@PathVariable解注解析;注解中required表示为空不接收;
(4)@RequestParam
属性:
@RequestParam(value = "u1",required = false,defaultValue = "default") String username
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true,如果为true没传值则400
defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时则使用默认值为形参赋值@RequestMapping(value = "/method02")public String method02(@RequestParam("name") String name,@RequestParam("age") Integer age,@RequestParam(value = "money", required = false) Double mon) {User user = new User();user.setName(name);user.setAge(age);user.setMoney(mon);return JSON.toJSONString(user);}
Spring框架
Spring中万物皆Bean,IoC和DI是Spring框架两大核心
一、IoC
IoC(Inversion of Control)控制反转,就是将对象创建的权力及对象的生命周期的管理交由Spring框架来处理。
1、 IoC底层原理
spring认为万物皆是bean,配置bean的位置,spring自动完成ioc
IOC底层是Map结构,Map
数据结类似: {"hello",new Hello()}
spring不能new一个对象,只能用反射创建对象,所以底层类似:
{"hello",Class.forName("cn.tedu.spring.Hello").newInstance() }
2、Spring中将类声明为Bean的注解
@Componnet
用于普通组件,定位不明
@Repository
一般用于持久层DAO,数据库交互
@Service
一般用于服务层Service,封装服务
@Controller
一般用于控制层Controller,用于与前端交互
四者使用没有区别,区别在于定位,后三者为Spring预留,后期可能会进行功能增强。当被扫描的不同的两个包中类名相同,可以给@Component注解加值@Component(value=“p1”)。启动类自动扫描本包及子包,所以启动类要在所有文件之上。
@Configuration:配置类
二、DI
自身对象中的内置对象是通过注入的方式进行创建。
public class Order {@Autowired User user;
}
三、AOP面向切面编程
切面本质为一个类,包含切点和通知,通知和切点本质为一个方法
1、五种切入方式
- 前置通知Before
- 后置通知After
- 环绕通知Around
- 返回后通知AfterReturning
- 异常通知AfterThrowing。后两者不可能同时执行
2、切面入门使用
添加APO依赖
org.springframework.boot spring-boot-starter-aop
定义切面,类上添加注解@Component @Aspect
定义切点(添加Pointcut注解的方法)
定义通知(添加Before注解的方法)
@Component
@Aspect
public class AopPojo {/** Pointcut* 作用:该注解表示是哪个路径里面方法触发* 参数列表:cn.tedu.service是包路径。 *表示1个 ..表示多个。 *依次代表方法返回值类型,类名,方法名,(..)是参数列表,都可具体到类和方法** 使用方法二: 注解里面的值为定义注解的路径* @Pointcut("@annotation(com.jt.resource.annotation.RequiredLog)")* */@Pointcut("execution(* com.hssmart.controller.*.*(..))")public void beforeText(){} //方法体为空,此方法中不需要写任何内容,只负责承载@Pointcut注解@Before("beforeText()")public void beforeMethod() {System.out.println("哈哈哈");}
}
3、环绕例子
@Around("beforeText()")public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {String methodName = pjp.getSignature().getName();// 得到参数数组Object[] args = pjp.getArgs();for (Object arg : args) {// 获取参数列表中HttpServletRequest对象,然后获取token值if (arg instanceof ShiroHttpServletRequest) {HttpServletRequest httpServletRequest = (HttpServletRequest) arg;System.out.println(httpServletRequest.getHeader("token"));}}//@BeforeSystem.out.println("【环绕前置通知】---"+ methodName +"---【方法开始】");//就是利用反射调用目标方法即可,就是 method.invoke(obj, args) 得到的proceed是目标方法的返回值Object proceed = pjp.proceed(args);//@AfterReturningSystem.out.println("【环绕返回通知】---"+ methodName +"---【方法返回,返回值 "+ proceed +"】");//反射调用后的返回值也一定返回出去,不返回会空指针return proceed;}
注意事项:通知返回值为Object,参数是被环绕方法的具体路径。
四、spring提供的注解
1.声明bean的注解
@Component 组件,通用的注解方式
@Service 在业务逻辑层使用(service层)
@Repository 在数据访问层使用(dao层)
@Controller 在表现层使用,控制器的声明(C)
@Configuration:配置类
2.注入bean的注解
@Autowired:由Spring提供
@Inject:由JSR-330提供
@Resource:由JSR-250提供
都可以注解在set方法和属性上,推荐注解在属性上(一目了然,少写代码)。
3.java配置类相关注解
@Configuration 声明当前类为配置类,相当于xml形式的Spring配置(类上)
@Bean 注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式(方法上)
@Configuration 声明当前类为配置类,其中内部组合了@Component注解,表明这个类是一个bean(类上)
@ComponentScan 用于对Component进行扫描,相当于xml中的(类上)
@WishlyConfiguration 为@Configuration与@ComponentScan的组合注解,可以替代这两个注解
4.切面(AOP)相关注解
Spring支持AspectJ的注解式切面编程。
@Aspect 声明一个切面(类上)
使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。
@After 在方法执行之后执行(方法上) @Before 在方法执行之前执行(方法上) @Around 在方法执行之前与之后执行(方法上)
@PointCut 声明切点
在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上)
5.@Bean的属性支持
@Scope 设置Spring容器如何新建Bean实例(方法上,得有@Bean)
其设置类型包括:
· Singleton (单例,一个Spring容器中只有一个bean实例,默认模式),
· Protetype (每次调用新建一个bean),
· Request (web项目中,给每个http request新建一个bean),
· Session (web项目中,给每个http session新建一个bean),
· GlobalSession(给每一个 global http session新建一个Bean实例)
@StepScope 在Spring Batch中还有涉及
@PostConstruct 由JSR-250提供,在构造函数执行完之后执行,等价于xml配置文件中bean的initMethod
@PreDestory 由JSR-250提供,在Bean销毁之前执行,等价于xml配置文件中bean的destroyMethod
@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。
6、@CrossOrigin 跨域
五、aop实现日志打印
-
添加依赖
在 pom.xml 文件中添加
spring-boot-starter-aop
依赖,例如:org.springframework.boot spring-boot-starter-aop -
自定义注解
定义一个用于标记需要记录日志的方法的注解,例如:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Loggable {String value() default ""; }
这个注解中,我们定义了一个 value 属性,用于设置日志信息的前缀。
-
编写切面逻辑
创建一个切面类,实现方法执行前后的日志记录逻辑。例如:
@Aspect @Component @Profile("dev") // 在切面逻辑中加入条件判断,只有在开发环境才执行日志记录逻辑 public class LoggingAspect {private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);@Before("@annotation(loggable)")public void logMethodExecution(JoinPoint joinPoint, Loggable loggable) { logger.info("=================start=========================================");String prefix = loggable.value();String methodName = joinPoint.getSignature().getName();String className = joinPoint.getTarget().getClass().getSimpleName();Object[] args = joinPoint.getArgs();logger.info("{}{}.{}({})", prefix, className, methodName, Arrays.toString(args));}@AfterReturning(value = "@annotation(loggable)", returning = "returnValue")public void logMethodReturnValue(JoinPoint joinPoint, Loggable loggable, Object returnValue) {String prefix = loggable.value();String methodName = joinPoint.getSignature().getName();String className = joinPoint.getTarget().getClass().getSimpleName();logger.info("{}{}.{}() returned {}", prefix, className, methodName, returnValue);}}
这个切面类实现了方法执行前后的日志记录逻辑,分别使用了
@Before
和@AfterReturning
注解来标记需要拦截的方法,并使用了自定义注解@Loggable
来标记需要记录日志的方法。在方法执行前后,我们通过获取 JoinPoint 对象中的信息来获取方法的参数和返回值,并将其记录到日志中。 -
在需要打印日志的方法上添加注解
在需要打印日志的方法上添加
@Loggable
注解,并可选地设置日志信息的前缀。例如:@Service public class MyService {@Loggable("MyService:")public void doSomething(String arg1, int arg2) {// ...}}
在这个示例代码中,我们在
doSomething
方法上添加了@Loggable("MyService:")
注解,将日志信息的前缀设置为 "MyService:"。 -
运行程序并查看日志输出
运行程序并调用
doSomething
方法,即可在控制台或日志文件中看到相应的日志输出。 -
结果
标签:
相关文章
-
无相关信息