摘要
前前后后花了好几个月的时间学习Java基础,感觉都是零零散散的知识点,不仅不知道实际当中怎么用,而且容易忘。所以,开始一个真正的应用很有必要,不仅可以整合前面所学的知识,更重要的是开始接触真正的工作内容。下面讲解如何从零开始,搭建一个SpringBoot容器。
1. 从一个空的文件夹开始
一个基本的Spring项目包括:
pom.xml文件src\main\java\hello\Application.javasrc\main\java\hello\HelloController.java

1.1 添加内容
pom(project-object-model),maven的配置文件,也是Java项目的核心文件。首先,按照官网的提示,在一个空的文件夹中新建
pom.xml文件,然后将Build With Maven中的内容粘贴到其中。
配置阿里云的镜像,以保证访问速度,在pom.xml中添加:
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
</repositories>
新建Application类以及HelloController类,同样按照提示将代码复制到其中。刷新Maven后,就可以发现这时候这个项目以及可以开始运行了。并且在浏览器中输入
lcoalhost:8080就可以看到这个项目已经启动了:

2. web应用的本质
2.1 处理HTTP请求
- 从HTTP请求中提取querystring(查询字符串)。
- 从HTTP中接受payload(负载)中的参数。
例如:我们在谷歌浏览器搜索栏中填入
springboot这时可以看到url变成了https://www.google.com/search?q=springboot&oq=springboot&aqs=chrome..69i57l2j69i60j69i61j69i60l2.2979j0j7&sourceid=chrome&ie=UTF-8
那么?后面这一系列的键值对就都称为查询字符串。补充说明一下:search在产品维度上称为接口。
2.2 返回HTTP响应
响应内容包括:
- status code
- HTTP response header
- HTTP response body
补充说明:
- 字节流中HTTP header与HTTP body之间用四个分隔符\r\n\r\n来分隔。
- body中又包括:JSON,HTML,CSS等
2.3 如何获取查询字符串
假设我们是Google,用户输入这样一个网址
http://localhost:8080//search?q=dog,那么我们要怎么拿到这个dog关键字呢?回到代码中:
//将接口名指定为/search
@RequestMapping("/search")
//请求的参数指定为q
public String search(@RequestParam("q") String searchKeyWord) {
return "you are searching:"+searchKeyWord;
}
重新点击运行,输入网址:

@RequestMapping("/search")
//将charset参数设置为非强制的
public String search(@RequestParam("q") String searchKeyWord,
@RequestParam(required = false,value = "charset") String charset) {
return "you are searching:"+searchKeyWord + " with charset is :"+charset;
}
GET请求通常用于传递非敏感信息,因为在GET请求中的账户名密码都是会显示在url中的,所以不能将敏感信息通过GET请求发送。
2.4 RESTful API
RESTful API是一套用于设计WEB数据接口的一套API设计规范,用以规范URL、状态码以及服务器的响应。developer.github.com/v3/ (github的API被称为业界的标杆,值得学习)。
- 使用HTTP动词来代表动作
- GET-获取资源
- POST-新建资源
- PUT-更新资源
- DELETE-删除资源
- 使用URL来代表资源
- 资源里面没有名词
- 使用复数来代表资源列表
以DELETE举例,spring中的代码如下:
@RestController
//把所有的请求映射到一个方法上
@RequestMapping("repos")
public class IssueController {
@DeleteMapping("/{owner}/{repo}/issues/{issuesNumber}/lock")
public void unlock(
@PathVariable("owner") String owner,
@PathVariable("repo") String repo,
@PathVariable("issuesNumber") String issueNumber
) {
System.out.println(owner+" "+repo+" "+issueNumber);
}
}
由于DELETE操作不能由浏览器发起,这里使用Postman模拟DELETE请求。


2.5 从HTTP post中获取body
当请求的参数非常多时,一般都是将参数至于HTTP post的body中,那么如何从HTTP的body中拿到参数呢?同样以GitHub的POST举例:
请求的路径为
POST /repos/:owner/:repo/issues
body为:
{
"title": "Found a bug",
"body": "I'm having a problem with this.",
"assignees": [
"octocat"
],
"milestone": 1,
"labels": [
"bug"
]
}
代码如下:
@PostMapping("/{owner}/{repo}/issues")
public void createAnIssue(
@PathVariable("owner") String owner,
@PathVariable("repo") String repo,
@RequestBody HashMap requestBody
){
System.out.println(requestBody);
}
同样使用PostMan模拟post请求:
url:http://localhost:8080/repos/hello/world/issues
body:


通过调试看到:

具体操作:
PostBody{title='Found a bug', body='I'm having a problem with this.', milestone=1, assignees=[octocat], labels=[bug]}。
2.6 从表单中获取body
代码如下:
@PostMapping("/getForm")
public void getForm(
@RequestParam("name") String name,
@RequestParam("city") String city
){
System.out.println(name);
System.out.println(city);
}
post请求如下:

zhangsan
beijin
可以看到,实现了从form表单中获取参数,这种方式适用于参数比较少的情况。
3.生成HTTP响应
通过前面的几种方式,我们拿到了HTTP请求中的参数,接下来就是作出合理的处理,然后生成HTTP响应给前端了。
首先我们知道,HTTP响应返回的本质上就是一个HTML文本,使用一些标记语言实现对结果的美化。所以最简单的操作,我们也可以在Java代码中直接添加HTML标签:
@RequestMapping("/getForm")
public String getForm(
@RequestParam("name") String name,
@RequestParam("city") String city
) {
//为返回结果添加标签
return ("<em>" + name + "</em>" + " " + "<strong>" + city + "</strong>");
}
结果:

@RequestMapping("/Servlet")
public void controlRawServlet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//返回一个status code=403错误
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
//将信息写入http reponse中
response.getWriter().write("hello world 403");
}
结果如下:

JSON字符串。在Spring中实现往http body中写入数据:@RequestMapping("/GetBody")
@ResponseBody
public Object writeIntoBody(){
Map<String,Object> map = new HashMap<>();
map.put("result", Arrays.asList("zhangsan","beijin"));
return map;
}
结果:


HttpMediaTypeNotAcceptableException意思就是不接受这种返回类型。4.提问
4.1 HTTP GET不能带body嘛?
参考自WebTechGarden的个人博客以及stackoverflow的回答:
首先HTTP协议中并没有规定GET中不能带body,并且作者采用多种方式证明了,HTTP GET是可以带body的。但是GET被设计来用URI来识别资源,如果让它的请求体中携带数据,那么通常的缓存服务便失效了,URI 不能作为缓存的 Key。
但另一方面,如果仅仅是为了读取资源,而需要使用 Body 发送一大批数据时,改用 POST 请求却与 RESTFul 的 post 语义不相符。这时候或许可以 GET + body, 但是不能对该请求以 URI 作为 Key 进行缓存了。
所以,在GET中添加body是没有意义的。
5. 必备知识
5.1 Servlet、Servlet容器
摘自:知乎.来之孤岛的鲸鱼
- Servlet
Java Servlet(Java服务器小程序)是一个基于Java技术的Web组件,运行在服务器端,它由Servlet容器所管理,用于生成动态的内容。 Servlet是平台独立的Java类,编写一个Servlet,实际上就是按照Servlet规范编写一个Java类。Servlet被编译为平台独立 的字节码,可以被动态地加载到支持Java技术的Web服务器中运行。
- Servlet容器
Servlet容器也叫做Servlet引擎,是Web服务器或应用程序服务器的一部分,用于在发送的请求和响应之上提供网络服务,解码基于 MIME的请求,格式化基于MIME的响应。Servlet没有main方法,不能独立运行,它必须被部署到Servlet容器中,由容器来实例化和调用 Servlet的方法(如doGet()和doPost()),Servlet容器在Servlet的生命周期内包容和管理Servlet。在JSP技术 推出后,管理和运行Servlet/JSP的容器也称为Web容器。

6. 参考资料:
1.个人博客.《谁说 HTTP GET 就不能通过 Body 来发送数据呢?》跳转至源文章
2. stackoverflow.“HTTP GET with request body” 跳转至源文章
3. 微信公众号: WebTechGarden.《99%的人都理解错了HTTP中GET与POST的区别》 跳转至源文章
4. 个人博客.《RESTful API 最佳实践》跳转至源文章
5. 知乎.《几个概念:Servlet、Servlet容器、Tomcat》跳转至源文章