Spring框架 - Web框架 实现Controller

实现Controller

实现基本的Controller并处理输入输出html

基本的Controller

添加了Controller Annotation声明该类是Controller
也添加RequestMapping,经过value制定的/hello的路径
咱们在函数处理以前也加了RequestMapping,经过value指定/spring这样的结果是当碰到/hello/spring就会把请求转接到Spring这个函数的处理
这个函数就输出信息。web

@Controller
@RequestMapping(value = "/hello")
public class HelloController {
    
        @RequestMapping(value = "/spring")
        public void spring(HttpSerlvetResponse response) throw IOException{
            response.getWriter().write("Hello, Spring Web!!");
            }
}

定义Controller

在Spring配置文件中,经过context:component-scan来自动扫描,这样咱们在所扫描包下的经过Controller Annotation定义Controller都会被加载WebApplicationContext做为实例正则表达式

<!-- 自动扫描Controller,自动扫描目录下的子包,不可以直接填写对应controller,会自动扫描@componetns 等注释,并注册Bean-->
       <context:component-scan base-package="com.hava"/>

@RequestMapping参数

  • name:名称
  • value&path:路径,如"/hello"
    能够不写
  • method:请求方法,如"GET"
    HTTP协议的请求方法,这里是为了限制请求的方法,若是碰到DELETE就不会处理。添加RequestMapping实际是为了限制哪些请求能够进入到这个函数当中。好比咱们制定的path是须要特定的请求,才可以进入到咱们的方法当中。method是指定HTTP请求的某些方法。才能被咱们的函数处理。
  • params:请求参数
    请求参数通常有两种形式进行处理,一种是在请求地址里面添加?,好比添加?key=value的这种形式的请求方法,能够经过与操做添加多个请求参数。也是为了限制特定的请求参数转发到这里
  • headers:请求头
    限制请求的头信息,好比自定义的header内容与信息,经过服务端的header进行配置
  • consumes:请求的媒体类型,与HTTP"Content-Type"对应
    只可以处理特定请求数据的Content-Type,好比json格式,咱们这里声明json格式,则请求方法就不能进行处理。
  • produces:响应的媒体类型,"Accept"
    能够指定只输出JSON,也能够执行只输出XML。一样的,能够根据Accept请求的类型输出对应的媒体类型。能够在请求的accept请求json,则返回json;accept请求xml返回xml。主要限制哪些请求能够被这个函数所处理。

@RequestMapping路径

  • RestAPI ?
    若是用原生Serlvet去处理,须要去作地址的解析,去解析对应的参数。在Spring当中,用Spring的,只须要定义以下的RequestMapping。咱们制定path的值,{userId}表明是变量,当访问URL在users以后跟的参数,咱们都认为是userId的值。而后在函数的参数部分添加@PathVariable,把userId的值做为这个函数的参数添加到这里。经过这种方式,只须要在这个方法上添加@RequestMapping就能够很好的处理路径参数匹配问题。
@RequestMapping(path = "/users/{userId}")
public String webMethod(@PathVariable String userId){
    // do work
}

@RequestMapping添加正则表达

咱们能够在RequestMapping中使用正则表达式,不过对格式有限制。以下示例表示,只有字母的userId。spring

@RequestMapping(path = "/users/{userId:[a-z]+}")
public String webMethod(@PathVariable String userId){
}

函数实现

首先咱们经过RequestMapping经过匹配达到某些条件的请求进入函数,对于以下示例的函数,参数有HttpServletResponse,自动的注入到response对象中。在实现里面,咱们经过response获取客户端的writer,把咱们想输出的信息输出到客户端。
须要注意的是,以下示例的函数返回值为void,为何咱们在这个函数内写response,response就能够拿到上下文信息,把咱们想要的信息输出到客户端当中。主要是由于Spring会对请求处理函数,作一些限制:能够注入哪些参数、有哪些种类的返回值。若是在请求参数里面设定参数,例如response参数,会在进入到这个函数的时候运行时会把相关的信息注入到函数当中。apache

@RequestMapping(value = "/spring")
public void spring(HttpServletResponse response) throw Exception{
    response.getWriter().write("Hello, Spring Web!!");
}

函数参数类型

  • HttpServletRequest/HttpServletResponse,HttpSession(Servlet API)
  • Reader/Writer
    能够直接注入Writer,是Java下面的包。Reader是和HttpRequest对应的,能够经过Reader读取请求内容
  • @PathVariable
    在请求地址中中匹配参数,叫作@PathVariable。能够编写@PathVariable的匹配请求路径中间的参数
  • @RequestParam
    匹配请求参数,例如URL地址?后面的,或者经过表单提交的。在Post方法的请求体里面。
  • @RequestHeader
  • HttpEntity
    Java里面的Spring定义的HttpEntity,有两种HttpEntity。一种是请求的HttpRequestEntity,一种是响应的HttpResponseEntity。
  • @RequestBody
    经过@RequestBody匹配整个请求体
  • Map/Model/ModelMap
    因为SpringMVC的功能,咱们也能够注入一些跟模型相关的功能。对于Spring来讲,能够获取通用意义上的Map,key-value的这种形式。也能够Spring本身定义的Model或者ModelMap。这两种都是和Map相似的key-value结构。做为模型注入函数当中。好比在参数中编写Map,Spring会自动把东西转化成Map对象,咱们就能够设置与返回结果Model相关的一些属性。

函数返回值

函数返回值是返回给用户的View的名称。json

  • void
    所表明的意义:函数返回值是返回用户的View的名称。可是若是这里返回void,表明请求处理函数不用去返回View。函数内部会处理与View相关的逻辑。
  • String
    通常状况下表明返回view的名称,也能够经过@ResponseBody这个Annotation,在函数级别作@RequestBody,表明返回的String,不是view名称,而是响应内容。
  • HttpEntity
    在函数参数当中的HttpEntity表明请求的HttpEntity,在返回值也能够加入HttpEntity(HttpResponseEntity),表明函数返回值。HttpEntity包含响应的Header、响应的内容。对应的函数参数的HttpEntity包含请求的Header、请求的内容。
  • View
    返回Spring所定义的View对象,表明View对象。返回View对象,是提示Spring如何查找最终输出的View。View是与模板相关。
  • Map
    表明咱们所要返回的Model是什么样子的。与请求参数当中的Map一致。能够经过返回值返回Model。也能够在函数参数里面注入一个对象,去修改Model。
  • Model
    Map与Model只是返回了一个Model,并无带View的信息。
  • ModelAndView
    指定好视图相关的内容,也指定了视图所对应的Model。

函数参数与返回值示例

下面的示例和咱们以前的示例相似,首先返回值是void。以后是函数参数:api

  • 第一个参数@PathVariable
    匹配到的名称叫作user,注入的对象是String类型的user。
  • 第二个参数@RequestParam
    好比在URL的?后段的参数,在表单提交时,请求体里面也能够添加这个参数。名称叫作msg,咱们最终指望,要么URL?后面的参数有msg,要么经过Post请求体里面有msg字段,来请求参数。
  • 第三个参数@RequestHeader
  • 第四个参数@HttpServletRequest
    HttpServletRequest是和HttpServletResponse相似。能够经过这种方式,直接拿到request对象。经过request对象拿到请求相关的信息。例如RequestHeader、RequestParam均可以经过这个对象获取,咱们是把咱们比较关心的信息直接匹配到参数当中。这样咱们就不须要再实际的函数当中添加RequestHeader、RequestParam的请求逻辑。
  • 第五个参数Writer
    咱们能够直接匹配Writer,在以前的示例里面,并无直接获取writer对象,而是经过注入的Response对象,获取writer对象。在函数实现里面,写一些展示给用户的内容。
@RequestMapping(value = "/spring/{user}")
public void spring(
    @PathVariable("user") String user,
    @RequestParam("msg") String msg,
    @RequestHeader("host") String host,
    HttpServletRequest request,
    Writer writer) throw IOException{
        writer.write("URI: " + request.getRequestURI());
        writer.write("Hello " + user + " : " + msg + " host=" + host);
}

使用场景

  • 简单表单
    通常状况下,最多的是表单,好比用户登陆,就是把用户名密码提交到服务端。能够经过@RequestParam获取username和password,把这两个字段的值匹配到对应的参数对象。咱们在实现逻辑就能够处理username和password的处理逻辑。
@RequestMapping(value = "/spring/login")
public void login(
    @RequestParam("username") String username,
    @RequestParam("password") String password,
    Writer writer) throw IOException{
    // do something with name and password
}
  • 复杂表单
    注册表单会有不少不少字段,若是咱们在函数内一一的注入字段,咱们须要编写不少@RequestParam的注入。Spring提供了 @ModelAttribute,经过@ModelAttribute的Annotation来匹配称做Model的Java对象,直接从参数里面匹配Model,上面的示例,简化匹配一个参数就能够了。以下示例咱们定义了User的Model类。包含两个字段,name&password。而后就能够像以下示例,经过@ModelAttribute注入user对象。会自动把user的name和password,经过表单注入到对象内。而后就能够经过对象,获取属性。
@RequestMapping(value = "/spring/login")
public void login(
    @ModelAttribute User user,
    Writer writer) throw IOException{
    // do something with name and password
}
  • 上传文件
    在表单里面有选择按钮,以后Button点击上传。在服务端处理,首先须要定义一个和文件上传相关的Bean。这个Bean叫作CommonsMultipartResolver,咱们通常把文件上传称做Multipart,当在Spring定义完CommonsMultipartResolver就能够简单使用了。Spring的Multipart是经过Apache commons的第三方库实现的。因此,若是要添加CommonsMultipartResolver,则须要在Maven中添加Apache Commons的依赖。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="100000" />
</bean>

当咱们定义好multipartResolver的Bean后,咱们就能够在参数中,经过@RequestParam注入MultipartFile的对象,直接把文件内容匹配当对象中。若是限定了函数的method是RequstMethod.POST方式。文件上传以POST方式上传。浏览器

@RequestMapping(path="/form",method=RequestMethod.POST)
public String handleFormUpload(@RequestParam("file") MultipartFile file){
    //save file
}
  • HttpEntity
    以下示例,请求参数也是HttpEntity,返回结果也是HttpEntity。能够看到函数匹配的参数是HttpEntity,也是有类型的,好比byte[],若是是写其余类型,则须要实现对应的转换器。在以下示例中是byte[],在注入requestEntity之后,能够经过requestEntity获取和Request相关的信息,例如获取到requestHeader、requestBody。最后,咱们能够返回一个ResponseEntity,能够设置responseHeader和responseBody相关的。以下示例返回的String类型。
@RequestMapping("/someting")
public ResponseEntity <String> handle(HttpEntity <byte[]> requestEntity){
    String requestHeader = requstEntity.getHeaders().getFirst("MyRequestHeader");
    byte [] requestBody = requestEntity.getBody();
    
    // do something with request header and body

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("MyResponseHeader","MyValue");
    
    return new ResponseEntity<String>("Hello",responseHeaders,HttpStatus.CREATED);
}
  • @RequestBody & @RsponseBody 函数返回的是String对象,注意若是不添加@ResponseBody,则返回的是view的名称。若是像以下的例子添加@responseBody,则是把String内容,放置到Response的body中。
@RequestMapping(value = "/spring")
@RequestBody
public String spring(@RequestBody String body) throws IOException{
    return "Hello " + body;
}
  • 返回对象? 咱们尝试经过@ResponseBody返回User对象,须要实际去尝试下,须要html页面提交表单。
@RequestMapping(value = "/spring/login")
@RequestBody
public User login(){
    User user = new User();
    
    return user;
}

**注意:**Tomcat会报错误。描述的是所返回的内容,不符合指定的媒体类型。例如,咱们经过浏览器进行返回,或者经过http的测试工具,来执行accept header,若是经过浏览器访问接口的话,accept通常会指定成textHtml页面。返回的是纯文本的内容。若是是经过特定指定的话,能够指定返回JSON,或者是XML。若是没有通过设置,则默认的是textHtml。本示例的意思为,浏览器所请求的是textHtml,可是返回的是数据对象。 输入图片说明服务器

  • MessageConverter
    Spring当中有MessageConverter,就是为了解决上面相似的问题,MessageConverter不只能够处理ResponseBody,也能够处理RequestBody,当处理RequestBody时,是指把RequestBody转化成对象参数。MessageConverter能够把Object转为成ResponseBody。Spring提供了一些基本的返回类型的Converter。这个须要在配置文件当中添加以下内容
<mvc:annotation-driven />

该配置就会自动添加一些Converter,好比说JSON相关的Converter还有XML相关的Converter,返回的User对象,因为打开了Converter会根据默认的Converter进行转换。因为默认的JSON、XML处理须要引用外部包,则须要在Maven中添加mvc

<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>2.6.4</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.6.4</version>
		</dependency>

代码开发实例

简单的HttpServletResponse

@Controller
public class HavaHelloController {

    @RequestMapping(value = "/response")
    public void response(HttpServletResponse response) throws IOException {
        System.out.println(response);
        response.getWriter().write("Hello,Spring Web!!");
    }
}

因为web.xml配置以下,访问的路径为/api/*

<servlet>
		<servlet-name>example</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>example</servlet-name>
		<url-pattern>/api/*</url-pattern>
	</servlet-mapping>

访问的URL:http://localhost:8080/api/response
后台输出

org.apache.catalina.connector.ResponseFacade@725005c5

注入Writer

@RequestMapping(value = "/write")
    public void write(Writer writer) throws IOException {
        System.out.println(writer);
       writer.write("Hello,Spring Web!!");
    }

访问的URL:http://localhost:8080/api/write
后台输出

org.apache.catalina.connector.CoyoteWriter@2e6c953a

获取URL当中的动态参数

@RequestMapping(value = "/user/{userId}")
    public void user(@PathVariable("userId") String userId,Writer writer) throws IOException {
        writer.write("userId= " + userId);
    }

访问的URL路径:http://localhost:8080/api/user/123
前台结果

userId= 123

获取RequestHeader信息

@RequestMapping(value = "/user-host/{userId}")
    public void user_host(@PathVariable("userId") String userId,
                          @RequestParam("msg") String msg,
                          @RequestHeader("host") String host,
                          Writer writer) throws IOException {
        writer.write("userId= " + userId + ", msg=" + msg + ", hostHeader=" + host);
    }

访问的URL路径:http://localhost:8080/api/user-host/123?msg=test_message 前台结果

userId= 123, msg=test_message, hostHeader=localhost:8080

若是没有添加msg,则Spring会给前段报异常
URL:http://localhost:8080/api/user-host/123

HTTP Status 400 - Required String parameter 'msg' is not present

type Status report

message Required String parameter 'msg' is not present

description The request sent by the client was syntactically incorrect.

用户名密码登陆

@RequestMapping(value = "/user/login")
    @ResponseBody
    public String login(@RequestParam("username") String username,
                      @RequestParam("password") String password,
                        @RequestHeader("host") String host) throws IOException{
        System.out.println("username:" + username);
        System.out.println("password:" + password);
        return "Username: " + username + "\n " + "Password: " + password + "\n Host:" + host;
    }

Html表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/api/user/login" method="post">
        <p>Name: <input type="text" name="username" /></p>
        <p>Password: <input type="text" name="password" /></p>
        <input type="submit" value="Submit" />
    </form>
</body>
</html>

注意:本例子中,html是没有web应用名称路径的,这个是因为编者使用的idea,直接运行的。而没有经过Maven进行运行。正常运行状态,还有Maven运行是带有web应用名称的,而idea须要单独设置Edit Configurations里面添加路径。
页面以及填入的信息 输入图片说明
后台输出

username:123
password:456

Chrome查看的跳转结果,注意URL发生了变化跳转到了http://localhost:8080/api/user/login而且显示以下结果

Username: 123 Password: 456 Host:localhost:8080

须要注意的是,咱们在输出的String添加\n字符做为回车,可是在输出的页面当中,并无进行换行。这时咱们监控Chrome的Response能够看到以下内容

Username: test123
 Password: test123
 Host:localhost:8080

Html须要添加html的换行,才可以显示换行。若是添加<p></p>则发生了换行。

重要错误

**注意:**若是函数返回类型为String,而且使用@ResponseBody做为函数的返回值,若是函数参数当中注入Writer writer,则会发生异常显现。在表单提交时,可以正确发送post请求,服务器也可以正确接收到参数内容。可是在输出时,会发生异常获取空白页面,经过Chrome的请求来看,仅仅可以看到response输出不完整错误信息。错误代号500

错误代码以下:

@RequestMapping(value = "/user/login")
    @ResponseBody
    public String login(@RequestParam("username") String username,
                      @RequestParam("password") String password,
                        @RequestHeader("host") String host,
                        Writer writer) throws IOException{
        System.out.println("username:" + username);
        System.out.println("password:" + password);
        return "Username: " + username + " " + "Password: " + password + " Host:" + host;
    }

Chrome的显示
输入图片说明
不完整的显示输出
输入图片说明

相关文章
相关标签/搜索