核心:IoC(Inverse of Control,控制反转),AOP(Aspect Oriented rogramming,面向切面编程)
控制权由应用代码中转到了外部容器(bean),控制权的转移,就是反转;
spring框架中,把创建对象的权利交给框架,包括依赖注入(DI:Dependency Injection)和依赖查找(不知道是什么?没看见过)
减少程序间的耦合(程序间的依赖关系)。
待写。
(有个老师说的)通过预编译的方式和运行期动态代理实现程序功能的统一维护技术。是OOP的延续,不是替代。
(网上的解释)使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。
从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事物管理,日志记录等等。
这些系统性的编程工作都可以独立编码实现,然后通过AOP技术切入进系统即可。从而达到了 将不同的关注点分离出来的效果。
在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码(一些重复代码提出来由切面实现);提高开发效率;维护方便。
待写。
类似Java语法。官方文档:https://velocity.apache.org/engine/devel/user-guide.html
#foreach($color in $collors)
Colors$!{foreach.count}/${foreach.index}:$!{color}
#end
#* 相当于
for(color:colors){
sout("Colors"+(count/index)+":"+color);
}
*#
4.模板继承:(为了减少功能重复的重复写)
include 纯文本扩展
parse 变量解析
## header.vm ##
Title $!title
#set($title = "nowcoder")
Include: #include("header.vm")
Parse: #parse("header.vm")
#* 输出:
Include: Title $!title
Parse: Title nowcoder
include只是把header里的文本包含进来,而parse对其进行了解析
*#
5.函数调用marco:
#macro (render_color, $color, $index)
Color By Macro $index, $color
#end
#foreach($color in $colors)
#render_color($color,$foreach.index)
#end
#* 输出
Color By Macro 0, RED
Color By Macro 1, GREEN
Color By Macro 2, BLUE
*#
6.设置变量:
#set($hi = "hi")
#set($hi1 = "$!{hi} world")
#set($hi2 = '$!{hi} world')
hi: $hi
hi1: $hi1
hi2: $hi2
#* 输出:
hi: hi
hi1: hi world
hi2: $!{hi} world
双引号进行了解析,单引号不会进行解析
*#
https://start.spring.io/
选择: Project:Maven Project
Language:Java
Spring Boot:2.1.7(之后会把版本改成老版本,所以现在随便)
Dependencies:Web, Velocity, AOP(新版本中没有Velocity(说不好用,只是为了学习用这个),后面两个找不到,在所以在之后加入)
点击Generate the project。将压缩包保存到要保存的项目文件夹。解压文件。
(不知道为什么,第一次导入时,那些src文件夹那些都没有,重新打开项目就有了)
修改spring boot版本和添加之前没有导入的dependency;还有加入其他的东西。
在src/main/java/com.xxxx路径里有一个已经生成的xxxApplication类,在这个路径(后称源文件)下新建controller,service包。
IndexController.java。
package com.xxx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@RequestMapping("/") // 括号内指定url
//@RequestMapping(path = {"/", "/index"}) 指定多个
@ResponseBody // 表示返回数据
public String index(){
return "home";
}
}
此时run那个xxxApplication类中的main。
端口为8080。在浏览器中输入127.0.0.1:8080/
返回一个打印了home的页面。
检查发现在src文件夹下并没有controller文件夹和indexcontroller类,好像是因为建到了target里了?重新在src路径下建立文件夹和类,运行后网页能访问了。
@RequestMapping(value = {"profile/{groupId}/{userId}"}) //url:127.0.0.1:8080/profile/groupid/userid?key=key&type=type
@ResponseBody
public String profile(@PathVariable("groupId") String groupId,
@PathVariable("userId") int userId,
@RequestParam(value = "type",defaultValue = "1") int type,
@RequestParam(value = "key",defaultValue = "no") String key){
return String.format("GID{%s},UID{%d},TYPE{%d},KEY{%s}",groupId,userId,type,key);
}
@PathVariable:路径变量
@RequestParam:请求参数
自己编写一个.vm文件,放在resource的template下。
//返回一个vm的模板:
@RequestMapping(value = {"/vm"})
public String news(Model model){
model.addAttribute("value1", "vv1"); //model的所有数据,数据的方法都可以在该vm文件里调用。
return "news"; // news为模板名称,也可以写成news.vm
}
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@RequestMapping("/request") // 括号内指定url
@ResponseBody // 表示返回文本
public String request(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
StringBuilder sb = new StringBuilder();
Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String name = headerNames.nextElement();
sb.append(name+":"+ request.getHeader(name)+"
");
}
return sb.toString();
}
输出:
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134
accept-language:zh-Hans-CN,zh-Hans;q=0.5
accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
upgrade-insecure-requests:1
accept-encoding:gzip, deflate
host:127.0.0.1:8080
connection:Keep-Alive
cookie:JSESSIONID=E20626934B8F900EB9EDADE9A4734256
@RequestMapping("/response") // 括号内指定url
@ResponseBody // 表示返回文本
public String response(@CookieValue(value="nowcoderid",defaultValue = "a") String nowcoderId,
@RequestParam(value = "key", defaultValue = "key") String key,
@RequestParam(value = "value", defaultValue = "value") String value,
HttpServletResponse response,
HttpSession session){
response.addCookie(new Cookie(key, value));
response.addHeader(key, value);
return "NowCoder From Cookie:" + nowcoderId;
}
// 进入127.0.0.1:8080/response?key=nowcoderid&value=22
// 输出:NowCoder From Cookie:22
1.重定向:
301:永久转移
302:临时转移
@RequestMapping("/redirect/{code}")
public RedirectView redirectView(@PathVariable("code") int code){
RedirectView red = new RedirectView("/",true);
if (code == 301){
red.setStatusCode(HttpStatus.MOVED_PERMANENTLY);
}
return red;
}
// 如果是301,第一次会跳到指定url,这里是首页。下次再访问时不会再向服务器请求,而是直接请求首页。如果是302,则每次访问都会进行请求。
2.错误:(抛异常)
@RequestMapping("/admin")
@ResponseBody
public String admin(@RequestParam(value = "key", required = false) String key){
if ("admin".equals(key)){
return "hello admin";
}
throw new IllegalArgumentException("key 错误");
}
// 自定义报错信息:
@ExceptionHandler
@ResponseBody
public String error(Exception e){
return "error: "+e.getMessage();
}
// 进入:http://127.0.0.1:8080/admin?key=3
// 输出:error: key 错误
依赖注入。
创建一个service类,用@Service注解。(只写了基于注解的方法)
@Service
public class ToutiaoService {
public String say(){
return "this is from ToutiaoService";
}
}
要在controller层调用service类,就在controller类里定义一个@Autowire注解的service类的变量。
@Autowired
private ToutiaoService toutiaoService;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
}
3.在IndexController中加入该切面类实例对象:
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
@Autowired
private ToutiaoService toutiaoService;
@RequestMapping("/") // 括号内指定url
//@RequestMapping(path = {"/", "/index"}) 指定多个url
@ResponseBody // 表示返回文本
public String index(HttpSession session){
logger.info("Visit Index");
return "home
"+session.getAttribute("msg")+"
"+toutiaoService.say();
}
}
// 访问主页后输出:2019-08-08 22:28:44.591 INFO 33916 --- [nio-8080-exec-2] c.n.toutiao.controller.IndexController : Visit Index
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Before("execution(* com.nowcoder.toutiao.controller.IndexController.*(..))")
public void beforeMehtod(JoinPoint joinPoint){
logger.info("before method: ");
}
@After("execution(* com.nowcoder.toutiao.controller.IndexController.*(..))")
public void afterMehtod(JoinPoint joinPoint){
logger.info("after method: ");
}
}
注意表达式中的包要写对!还有除了加上@Aspect还有@Component,不然执行不了这两个通知。(因为没有将当前类对象存入spring容器中)