[牛客网中级项目]第二章 spring入门和模板语法(笔记+)

目录

  • 1.spring框架基础
    • 1.1 spring框架:
    • 1.2 IoC:
      • 1.2.1 IoC的概念:
      • 1.2.2 IoC的目的/作用:
      • 1.2.3 IoC环境搭建:
    • 1.3 AOP:
      • 1.3.1 AOP的概念:
      • 1.3.2 AOP的作用:
      • 1.3.3 AOP配置:
  • 2.Velocity模板语法
  • 3.项目的spring环境搭建
    • 1. 进入spring initializer:
    • 2. 在IDEA导入刚才的文件中的pom.xml。
    • 3. 修改pom.xml。
    • 4. 写一个最简单的网页。
      • 4.1 在controller包里新建类
        • 4.1.1 (2019.8.2新的bug出现了):无法访问页面:
      • 4.2 指定更多url:
      • 4.3 返回一个模板而不是简单的数据:
      • 4.4 在源文件新建model包,自定义一个User类。
      • 4.5 request/response
      • 4.6 重定向和错误
  • 5. IoC
    • 5.1 创建service业务层
  • 6. AOP

1.spring框架基础

1.1 spring框架:

核心:IoC(Inverse of Control,控制反转),AOP(Aspect Oriented rogramming,面向切面编程)

1.2 IoC:

1.2.1 IoC的概念:

控制权由应用代码中转到了外部容器(bean),控制权的转移,就是反转;
spring框架中,把创建对象的权利交给框架,包括依赖注入(DI:Dependency Injection)和依赖查找(不知道是什么?没看见过)

1.2.2 IoC的目的/作用:

减少程序间的耦合(程序间的依赖关系)。

1.2.3 IoC环境搭建:

待写。

1.3 AOP:

1.3.1 AOP的概念:

(有个老师说的)通过预编译的方式和运行期动态代理实现程序功能的统一维护技术。是OOP的延续,不是替代。
(网上的解释)使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。
从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事物管理,日志记录等等。
这些系统性的编程工作都可以独立编码实现,然后通过AOP技术切入进系统即可。从而达到了 将不同的关注点分离出来的效果。

1.3.2 AOP的作用:

在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码(一些重复代码提出来由切面实现);提高开发效率;维护方便。

1.3.3 AOP配置:

待写。

2.Velocity模板语法

类似Java语法。官方文档:https://velocity.apache.org/engine/devel/user-guide.html

  1. 注释:## 注释 ## #*多行注释 *#
  2. $!{变量/表达式} 取变量或表达式的值。加了!表示如果变量不存在就不显示了。
  3. for循环:
#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
双引号进行了解析,单引号不会进行解析
*#

3.项目的spring环境搭建

1. 进入spring initializer:

https://start.spring.io/
选择: Project:Maven Project
Language:Java
Spring Boot:2.1.7(之后会把版本改成老版本,所以现在随便)
Dependencies:Web, Velocity, AOP(新版本中没有Velocity(说不好用,只是为了学习用这个),后面两个找不到,在所以在之后加入)
点击Generate the project。将压缩包保存到要保存的项目文件夹。解压文件。

2. 在IDEA导入刚才的文件中的pom.xml。

(不知道为什么,第一次导入时,那些src文件夹那些都没有,重新打开项目就有了)

3. 修改pom.xml。

修改spring boot版本和添加之前没有导入的dependency;还有加入其他的东西。

[牛客网中级项目]第二章 spring入门和模板语法(笔记+)_第1张图片

[牛客网中级项目]第二章 spring入门和模板语法(笔记+)_第2张图片
同时还需要修改test里的代码。改为如下:
[牛客网中级项目]第二章 spring入门和模板语法(笔记+)_第3张图片

4. 写一个最简单的网页。

在src/main/java/com.xxxx路径里有一个已经生成的xxxApplication类,在这个路径(后称源文件)下新建controller,service包。

4.1 在controller包里新建类

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。[牛客网中级项目]第二章 spring入门和模板语法(笔记+)_第4张图片
端口为8080。在浏览器中输入127.0.0.1:8080/
返回一个打印了home的页面。

4.1.1 (2019.8.2新的bug出现了):无法访问页面:

[牛客网中级项目]第二章 spring入门和模板语法(笔记+)_第5张图片
检查发现在src文件夹下并没有controller文件夹和indexcontroller类,好像是因为建到了target里了?重新在src路径下建立文件夹和类,运行后网页能访问了。

4.2 指定更多url:

@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:请求参数

4.3 返回一个模板而不是简单的数据:

自己编写一个.vm文件,放在resource的template下。

//返回一个vm的模板:
@RequestMapping(value = {"/vm"})
public String news(Model model){
    model.addAttribute("value1", "vv1");    //model的所有数据,数据的方法都可以在该vm文件里调用。
    return "news";   // news为模板名称,也可以写成news.vm
}

4.4 在源文件新建model包,自定义一个User类。

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;
    }
}

4.5 request/response

  1. request:参数解析,cookie读取,http请求字段,文件上传
    request.getHeaderNmaes();
    request.getMethod();
    request.getPathInfo();
    request.geiQueryString():
@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
  1. response:页面内容返回,cookie下发,http字段设置,headers
    reponse.addCookie(new Cookie(key, value));
    response.addHeader(key,value);
@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

4.6 重定向和错误

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 错误

5. IoC

依赖注入。

5.1 创建service业务层

创建一个service类,用@Service注解。(只写了基于注解的方法)

@Service
public class ToutiaoService {

    public String say(){
        return "this is from ToutiaoService";
    }
}

要在controller层调用service类,就在controller类里定义一个@Autowire注解的service类的变量。

@Autowired
private ToutiaoService toutiaoService;

6. AOP

  1. 建立一个aspect包,用来装切面类
  2. 创建一个切面类:用来记录日志
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
  1. 加入注释:@before,@After等。表示通知的执行顺序在切点前或切点后。

@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容器中)

你可能感兴趣的:(项目一笔记)