Spring是一个相当不错的Java框架,完善简洁美好。简单记录一下一个使用了Mysql数据库的Hello World项目搭建流程和我的思考。思考未必完备,参见官方文档:http://spring.io/guides/gs/rest-service/
我们的结果:
我们向以下链接发送HTTP GET
请求:
将会得到这样的文本:
Hello, Cheney !
如果向以下链接发送HTTP GET
或POST
请求,带有一个id
参数,内容为一个正整数
:
如果能在数据库中找到对应项,将会得到这样的json数据
:
{"id":0,"message":"Today we eat Potato"}
如果不能在数据库中找到对应项,将会得到如下:
{"id":1,"message":"ID Not Found"}
如果发送的请求中,id
不存在或者不是正整数则会得到如下json数据
:
{"id":2,"message":"ID Illegal"}
一、新建项目
填写包路径,一般为域名倒叙。
Dependences
选择 "Web"、"Rest Repositories"、"MySQL"、"JPA":
然后点击“Generate Project”就会生成一个Demo项目。
直接用Intellij IDE打开这个项目。注意不是导入。
二、配置application.yml
这一步是为了连接数据库、设置持久连接、配置本地调试服务器端口、配置jpa
首先把src/main/resources
目录下的application.properties
改名为application.yml
然后填入:
server:
port: 8081
这样这个Demo工程内嵌的Tomcat就会监听8081
端口了。不过Tomcat异常的矫情倒是一开始让我浪费了很多时间。
一个PHPer对Tomcat常见的无知
1.在star.spring.io
上生成的项目里会自带Tomcat。
2.如果程序出现问题,Tomcat会无法启动。(PHP中不管PHP-fpm还是Apache都很少因为程序问题无法运行)
3.如果数据库无法连接,Tomcat会无法启动。
4.代理软件会影响Tomcat的启动。
接着填:
spring:
resources:
chain:
enabled: true
datasource:
url: jdbc:mysql://192.168.207.134:3306/test
username: root
password: root
test-while-idle: true
validation-query: SELECT 1
jpa:
show-sql: true
hibernate:
ddl-auto: update
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
至于如何在虚拟机或者本地搭建mysql在此就不赘述了,mac下直接brew install mysql
。
以上就配置好了application.yml
三、写一个Hello World!
由于我们是遵循MVC模式的开发,所以我们进入src/main/java/cn.net.wangchenyu.springapidemo1
,新建两个package
,一个名字叫controllers
另一个叫models
:
然后我们在controllers
包下新建一个Java Class
,名字叫IndexController
,遵循大驼峰命名法。
在类声明语句的上方我们用@RestController声明这个类是一个RestController
,那么它就会返回json数据
。
然后我们使用@RequestMapping("/")
来绑定/
这个路径执行下面的indexShow
方法,方法名遵循小驼峰命名法。
于是IndexController
的内容如下:
package cn.net.wangchenyu.springapidemo1.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by cheneyveron on 7/7/16.
*/
@RestController
public class IndexController {
@RequestMapping("/")
public String indexShow(){
return "Hello Cheney!";
}
}
现在我们点击上面的绿色运行按钮,等待编译完了以后就可以在浏览器打开localhost:8081
了。
四、操作数据库
在Models
下新建CreateFood
类,类声明上方用@Entity
表明这是一个实体。然后用@Table(name = "Food")
指定对应的表为food
。
在建表的时候所有的字符都是小写的。
在id
项前面用@Id @GeneratedValue(strategy = GenerationType.AUTO)
声明这是一个主键并且自增。
String
声明的name
在数据库中会以varchar(255)
来储存。
CreateFood
完整文件:
package cn.net.wangchenyu.springapidemo1.models;
import javax.persistence.*;
/**
* Created by cheneyveron on 7/7/16.
*/
@Entity
@Table(name = "Food")
public class CreateFood {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
}
Mac下按Command + N
可以自动补全Getter
方法和Setter
方法。
为了管理Food
表,我们再创建一个名为CreateFoodDao
的Interface
,继承CrudRepository<T, ID>
,这里T
就是CreateFood
,ID
就是Integer
。
这样以后,我们只需要声明一个CreateFoodDao
对象,就能直接使用findOne(id)
,findAll
,save
这些方法了。
CreateFoodDao.java
内容:
package cn.net.wangchenyu.springapidemo1.models;
import org.springframework.data.repository.CrudRepository;
/**
* Created by cheneyveron on 7/7/16.
*/
public interface CreateFoodDao extends CrudRepository<CreateFood,Long> {
}
为了规范返回值,再在Models下建立一个ReturnMessage类,有两个属性,id和message:
package cn.net.wangchenyu.springapidemo1.models;
/**
* Created by cheneyveron on 7/7/16.
*/
public class ReturnMessage {
private int id;//返回代码标示
private String message;//返回信息
}
五、插入与读取数据库
我们在IndexController
中建立一个路径映射到/create
,然后建立一个方法create
。
在Create
方法中,我们先实例化一个CreateFood
对象,然后设置对象的name
属性。
如何保存呢?
在IndexController
中,我们建立一个@Autowired
的CreateFoodDao
对象createFoodDao
。然后调用createFoodDao
的save
方法,传入上面的createFood
对象即可保存。
坑1:注意!
这里的Object
不是org.omg.CORBA.Object
,而是java.lang.Object
包。如果你不小心引入了org.omg.CORBA.Object
只需要删除该引用即可,java.lang
不需要引入。
如今的IndexController.java
如下:
@RestController
public class IndexController {
@Autowired
private CreateFoodDao createFoodDao;
@RequestMapping("/")
public String indexShow(){
return "Hello Cheney!";
}
@RequestMapping("/create")
public Object create(){
CreateFood createFood = new CreateFood();
createFood.setName("Tomato");
return createFoodDao.save(createFood);
}
}
访问/create
就会看到创建的对象:
{"id":1,"name":"Tomato"}
更改一下名字,我们再多插入几条:
{"id":2,"name":"Potato"}
{"id":3,"name":"Cucumber"}
如何读取呢?
我们再映射一个路径到/showall
,直接返回createFoodDao.findAll()
方法即可:
@RequestMapping("/showall")
public Object showAll(){
return createFoodDao.findAll();
}
访问
就会看到:
[{"id":1,"name":"Tomato"},{"id":2,"name":"Potato"},{"id":3,"name":"Cucumber"}]
我们查看数据库,也会看到数据已经插入进去:
六、传递参数
接下来我们试着通过id
来寻找食物。
在IndexController
中建立一个路径映射到/verify,使用@RequestMapping("/verify")即可。
如何指定只接受POST传值?
只要这样写:@RequestMapping(value = "/verify",method = RequestMethod.POST)
就能只接受POST的值了。
默认情况下是GET
和POST
都接受。
接受参数的方式有三种。
1.直接写在形参位置
@RequestMapping(value = "/verify")
public Object verify(String stringId){
return stringId;
}
我们访问
就会返回:
5
注意
传参的时候参数名称区分大小写,必须和形参stringId
一模一样才能匹配。
2.自动匹配对象的属性
我们如果在参数的位置上写一个对象,那么传的参数会自动匹配到对象的属性。
@RequestMapping(value = "/verify")
public Object verify(ReturnMessage returnMessage){
return returnMessage;
}
我们访问
就会返回:
{"id":5,"message":"ab\"c 's "}
注意
1.传参的时候参数名称仅首字母不区分大小写。
2.私有属性如果没有setter
/getter
方法则无法设置/获取该属性。
3.使用@RequestParam
指定参数
@RequestMapping(value = "/verify")
public Object verify(@RequestParam(value = "id",defaultValue = "-1") String stringId){
return stringId;
}
我们访问
就会返回:
5
注意
必须和value
指定的名字id
一模一样才能匹配。
七、完成我们的API
Java的强类型性
和“空指针出错”
性让web开发很头疼。如果直接指定int类型
参数那么如果空参数就会直接报500错误。
为了让我们的API服务具有更强的容错性
,我们可以用String
类型来接收参数。整个函数头定义类似于此:
public Object verify(@RequestParam(value = "id",defaultValue = "-1") String stringId){
然后我们在函数内部执行Interger.parseInt(stringId)
来强转成Int型。
如果是纯数字,那么parseInt
会返回数字。
如果是含有非数字字符,那么parseInt
会抛出NumberFormatException
异常。
然后我们使用createFoodDao.findOne()
方法,传入id
来得到一个CreateFood
对象createFood
。
如果数据库能查询到,那么会返回一个CreateFood
对象createFood
。
如果查询不到,会返回null
。
接下来通过判断id
的值来设置returnMessage
,最后返回returnMessage
即可。
整个verify()
函数如下:
@RequestMapping(value = "/verify")
public Object verify(@RequestParam(value = "id",defaultValue = "-1") String stringId){
long id = -1;
try{
id = Integer.parseInt(stringId);
}catch (Exception e){
id = -1;
}
CreateFood createFood = createFoodDao.findOne(id);
ReturnMessage returnMessage = new ReturnMessage();
if(id < 0){
returnMessage.setId(2);
returnMessage.setMessage("ID Illegal");
}else if(createFood == null){
returnMessage.setId(1);
returnMessage.setMessage("ID Not Found");
}else{
returnMessage.setId(0);
returnMessage.setMessage("Today we eat"+createFood.getName());
}
return returnMessage;
}
至此,一个功能完备,并且具有一定的容错能力的的食物查询API已经做成啦。
Comments | 5 条评论
雨晴 博主
微晨风景,有实力,支持原创!
ting 博主
自由的分享与思考
会飞花语的微博 博主
Spring是一个相当不错的Java框架
小青草 博主
沙发抢不到了,咱抢个楼层
柯微 博主
收藏