Servlet、springMVC、springBoot

135 阅读7分钟

Servlet

创建servlet

public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求信息编码集,只对POST有效
        req.setCharacterEncoding("utf-8");
​
        //设置响应信息的MIME类型和编码集
        resp.setContentType("text/html;charset=utf-8");
        //根据表单名,得到表单值
        String userName = req.getParameter("userName");
​
        //向客户端输出文本信息
        resp.getWriter().print("Hello,"+userName);
    }
}

创建并启动tomcat

public class Main {
    public Main(){
        Tomcat tomcat = new Tomcat();
        //设置tomcat端口
        tomcat.setPort(8088);
        //引导http引擎
        tomcat.getConnector();
​
        //定义上下文
        Context context = tomcat.addContext("",null);
        //注册servlet:
        //第一个参数为上下文对象,第二个参数为servlet名称,第三个参数为servlet实现类对象。
        Wrapper wp = Tomcat.addServlet(context,"test",new TestServlet());
        //容器一启动就初始化
        wp.setLoadOnStartup(1);
        //配置servlet的访问路径
        wp.addMapping("/abc");
​
        try {
            //启动tomcat
            tomcat.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
​
    public static void main(String[] args) {
        new Main();
    }
}

映射路径

Servlet 映射路径有三种:

1、精确映射:/add

表示客户端以 /add 路径请求,就能找到对应的 servlet。

2、扩展映射:*.do

表示客户端以 .do 结尾的请求,都能找到对应的 servlet。

3、路径映射:/abc/*

表示客户端以 /abc/ 路径的请求,都能找到对应的 servlet

获取表单数据

//根据表单名,得到表单值
String value = req.getParameter("表单名"));
​
//得到多个同名键值对的值,返回数组
String[] array = req.getParameterValues("表单名");
​
//得到表单数据中的表单名枚举
Enumeration<String> em = req.getParameterNames();

Servlet的生命周期

1、容器加载并实例化 Servlet。

2、调用 init() ,完成初始化。

LoadOnStartup() 为 0 或正数,表示容器一启动就初始化;如果为负数或不写,表示第一次访问 Servlet 再做初始化。

3、当请求到达,调用 service() ,处理请求,产生响应。

4、销毁阶段,调用 destroy() 完成清理。

在整个生命周期中,1、2、4 都只做一次。只有第 3 步,才是每次请求都会执行。而 Servlet 对象也是单实例多线程的对象。


WEB 容器向客户端发送数据的方式有两种:

1、向客户端发送文本数据:

response.getWriter().print("添加成功!");

2、向客户端发送二进制数据:

OutputStream out = response.getOutputStream();

spring MVC

概念

spring MVC 是一个基于 MVC 模式的表现层框架。

特点

1、基于的是 servlet 模式。

2、控制器不再需要继承其他类,只需要用 @Controller 注解。

3、应用控制器方法参数,由前端控制器负责封装,方法签名定义灵活。

4、返回页面直接在方法中指定,可以是String,也可以是其他的,比如:ModelAndView 或 void 等。

5、性能也很优秀。

控制器分类

在 spring MVC 中存在两种控制器:前端控制器 和 应用控制器。

前端控制器(DispatcherServlet)本身就是 servlet,负责接收客户端请求,根据请求路径访问应用控制器,负责将页面参数填充 JavaBean ,负责转发页面,对标签类进行调用。

应用控制器(用户书写的 Controller),负责产生业务组件,调用业务组件的方法完成业务,根据结果返回转发的页面对象。

工作流程

spring MVC的工作流程:

1、当客户端请求服务器,服务器使用前端控制器 DispatcherServlet 接收请求。

2、DispatcherServlet 借助 HandlerMapping,根据请求的 URL 路径,定位到具体的 Controller,和应用控制器的具体方法。并将封装好数据的实体对象传入应用控制器方法。

3、由应用控制器方法,完成业务组件的业务方法的调用,然后根据业务方法处理的结果,返回需要转发的页面路径。DispatcherServlet 根据路径,完成页面转发。

spring Boot

概念

spring Boot 其设计目的是用来简化新 Spring 应用的初始化搭建以及开放过程。

spring Boot 框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,spring Boot 致力于在蓬勃发展的快速应用开发领域成为领导者。

spring Boot 是由一系列启动器组成的,这些启动器构成一个强大的灵活的开发助手。开发人员根据项目需要,选择并组合相应的启动器,就可以快速搭建一个合适项目需要的基础运行框架。

环境搭建

在父工程中,添加依赖:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> 
</parent>

添加 WEB 启动器坐标:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

创建启动类:

@SpringBootApplication  //标识该类为 springBoot 启动类
public class Main {
    public static void main(String[] args) {
        //启动 tomcat 容器,并完成初始化,扫描启动类所在包,及子包中的 spring 组件
        SpringApplication.run(Main.class);
    }
}

编写应用控制器:

注意:应用控制器必须建在启动类所在包的子包中。

@RestController//应用控制器
public class TestController {
    @RequestMapping("/speak")//客户端以/speak路径请求,就可以访问该方法
    public String speak(){
        return "说话";
    }
​
    @RequestMapping("/add")//客户端以/add路径请求,就可以访问该方法
    public String add(){
        return "添加";
    }
}

springBoot 的配置文件:

springBoot 由很多的自动配置,在开发中,我们可能需要修改 springBoot 自动配置的默认值。比如,服务器启动端口,数据源等。

springBoot 的配置文件名称时固定的,application.yml 或 application.properties,需要在 maven 项目中的 resources 目录中创建。


修改服务器启动端口:

application.properties :

server.port=8088

application.yml :

server:
  port: 8088

springBoot 静态资源:

springBoot 静态资源存放目录,需要在 classPath 类路径下。如果是 maven 工程,需要放在 resource 目录下。META-INF/resources、 resources、static、public 可以任选一个作为静态资源存放目录。

META-INF/resources > resources > static > public


在应用控制器中,得到表单数据:

<form action="/land" method="post">
    用户名:<input type="text" name="userName"><br>
    密码:<input type="password" name="password"><br>
    <input type="button" value="登陆">
</form>

应用控制器:

应用控制器中得到表单数据,可以在方法中定义形参得到。

@RestController
public class UserController {
    //要求表单名和形参名一致。
    //如果表单名和形参名不一致,需要加入@RequestParam(表单名)表示该表单名对应的表单值,赋值给当前形参。
    @RequestMapping("land")
    public String login(String userName, String password) {
        if ("lili".equals(userName) && "123".equals(password)) {
            return "登陆成功";
        } else {
            return "登陆失败";
        }
    }
}

如果应用控制器形参为实体 Bean,会按属性名和表单名一致的原则,进行属性值的填充。

@RequestMapping("land")
public String login(UserBean user) {
}

springMVC 中有默认的类型转换器,可以对大部分类型进行转换。不过,在开发中,有些时候需要根据业务自定义转换规则。默认情况下,springMVC 不支持 LocalDate 的转换。

@Component
public class LocalDateChange implements Converter <String, LocalDate>{
    @Override
    public LocalDate convert(String source) {
        if (source != null && source.matches("\d{4}-\d{2}-\d{2}")){
            return LocalDate.parse(source);
        }
        return null;
    }
}

同一个 URL 路径不能用于两个应该控制器方法的。但是在开发中,有些时候可能会有两个方法使用同一个 URL 路径的情况,这是应该用命令空间防止 URL 同名。

@RestController
@RequestMapping("user")
public class UserController {
    @RequestMapping("land")
    public String login(String name, String password, UserBean user) {
    }

访问 login 方法的路径为 /user/land。

<form action="/user/land" method="post">

表单中的 URL 路径问题:

<form action="user/land">

action 中,如果 URL 路径没有以 / 开始,那么表示在当前目录下查找资源。

<form action="/user/land">

action 中,如果 URL 路径以 / 开始,表示在根目录下查找资源。


在应用控制器中,可以申明该方法只能以某种请求方式进行访问。

@RequestMapping(value = "add",method = RequestMethod.POST)
public String add(UserBean user){
}

method = RequestMethod.POST :表示该方法只能以 POST 方式访问,否则会抛出 405 异常。

也可以直接使用@PostMapping、@GetMapping 代替 @RequestMapping,指定请求方式。


从 URL 路径中,得到请求数据:

方式一:

Html:

<a href="/user/del?id=5">删除</a>

应用控制器:

//表示形如/user/del/XX 路径的请求,由该方法处理
@RequestMapping("del")
public String del(int id){
    return "删除编号"+id;
}

方式二:

Html:

<a href="/user/del/5">删除</a>

应用控制器:

//表示 URL 路径中 userId 表示的内容,赋值给 id 形参
@RequestMapping("del/{userId}")
public String del(@PathVariable("userId") int id){
    return "删除编号"+id;
}

请求参数的默认值:

@RequestMapping("update")
//表示如果表单名为 id 的表单值为 null,则将默认值0,赋给形参 id;
//如果不为null,则将表单 id 的值赋给形参 id。
//defaultValue = "0" :默认值为0
public String update(@RequestParam(value = "id",defaultValue = "0") int id){
    return "修改"+id;
}

在应用控制器中,访问 WEB 容器中的请求/响应对象

在应用控制器中,有些应用可能需要访问容器中的请求响应对象,直接在应用控制器方法中,申明形参即可。

@RequestMapping("update")
public String update(@RequestParam(value = "id",defaultValue = "0") int id,
HttpServletRequest request, HttpServletResponse response){
    return "修改"+id;
}

@RequestMapping("show")
public List<LinkBean> showLink(){
    List<LinkBean> list = new ArrayList<>();
    list.add(new LinkBean("lisa",LocalDate.parse("2001-08-18"),"15167287671"));
    return list;
}

如果方法返回的是集合,或实体类对象,会将集合、实体类对象,以 json 字符串方式发送给客户端。