知乎專欄 | 多維度架構 | | | 微信號 netkiller-ebook | | | QQ群:128659835 請註明“讀者” |
@RequestMapping("/get/{id}") public Member getStatistics(@PathVariable long id) { Member statistics = memberRepostitory.findOne(id); if (statistics == null) { statistics = new Member(); } return statistics; }
MediaType.APPLICATION_JSON_VALUE 執行結果反饋json數據
@RestController @RequestMapping("/api/persons") public class MainController { @RequestMapping( value = "/detail/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE ) public ResponseEntity<Persons> getUserDetail(@PathVariable Long id) { Persons user = personsRepository.findById(id); return new ResponseEntity<>(user, HttpStatus.OK); } }
@RequestMapping(value = "/create", method = RequestMethod.POST, produces = { "application/xml", "application/json" }) public ResponseEntity<Member> create(@RequestBody Member member) { memberRepository.save(member); return new ResponseEntity<Member>(member, HttpStatus.OK); }
package api.config; import java.io.IOException; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; @Configuration public class JacksonConfig { @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() { @Override public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { jsonGenerator.writeString(""); } }); return objectMapper; } }
restful 將同時支持 json 和 xml 數據傳遞
package com.example.api.restful; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.example.api.domain.RecentRead; import com.example.api.repository.RecentReadRepostitory; @RestController @RequestMapping("/restful/article") public class ArticleRestController { @Autowired private RecentReadRepostitory recentReadRepostitory; @RequestMapping(value = "/recent/read/add/{memberId}/{articleId}", method = RequestMethod.GET, produces = { "application/xml", "application/json" }) public ResponseEntity<RecentRead> recentAdd(@PathVariable long memberId, @PathVariable long articleId) { RecentRead recentRead = new RecentRead(); recentRead.setMemberId(memberId); recentRead.setArticleId(articleId); recentReadRepostitory.save(recentRead); return new ResponseEntity<RecentRead>(recentRead, HttpStatus.OK); } @RequestMapping(value="/recent/read/list/{id}", produces = { "application/xml", "application/json" }) public List<RecentRead> recentList(@PathVariable long id) { int page = 0; int limit = 20; List<RecentRead> recentRead = recentReadRepostitory.findByMemberId(id, new PageRequest(page, limit)); return recentRead; } }
開發中發現很多人不適應新的介面方式,有時候只能妥協,這些頑固不化的人需要這樣的資料庫格式
{ "status":true, "reason":"登錄成功", "code":1, "data":{ "id":2, "name":null, "sex":null, "age":0, "wechat":null, "mobile":"13113668890", "picture":null, "ipAddress":"0:0:0:0:0:0:0:1" } }
返回數據必須放在 data 字典中, 而我通常是採用 http status code 來返回狀態,返回結果是對象。實現上面的需求我們需要加入一個data成員變數,因為我們不清楚最終要返回什麼對象。所以聲明為 java.lang.Object
package com.example.api.pojo; import java.io.Serializable; public class RestfulResponse implements Serializable { /** * */ private static final long serialVersionUID = -4045645995352698349L; private boolean status; private String reason; private int code; private Object data; public RestfulResponse(boolean status, int code, String reason, Object data) { this.status = status; this.code = code; this.reason = reason; this.data = data; } public boolean isStatus() { return status; } public void setStatus(boolean status) { this.status = status; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } @Override public String toString() { return "RestfulResponse [status=" + status + ", reason=" + reason + ", code=" + code + ", data=" + data + "]"; } }
Service
public RestfulResponse bindWechat(String mobile, String wechat) { Member member = memberRepository.findByMobile(mobile); member.setWechat(wechat); memberRepository.save(member); return new RestfulResponse(true, 1, "微信綁定成功", member); }
Controller
@RequestMapping("/login/sms/{mobile}/{code}") public RestfulResponse sms(@PathVariable String mobile, @PathVariable String wechat) { return memberService.bindWechat(mobile, wechat); }
@RequestMapping(value = "/list", method=RequestMethod.GET) public Page<Blog> getEntryByPageable1(@PageableDefault( sort = { "id" }, direction = Sort.Direction.DESC) Pageable pageable) { return blogRepository.findAll(pageable); } @RequestMapping(value = "/blog", method=RequestMethod.GET) public Page<Blog> getEntryByPageable(@PageableDefault(value = 15, sort = { "id" }, direction = Sort.Direction.DESC) Pageable pageable) { return blogRepository.findAll(pageable); } @RequestMapping(value = "/list", method=RequestMethod.GET) public Page<Blog> getEntryByPageable2(@PageableDefault Pageable pageable) { return blogRepository.findAll(pageable); } @ModelAttribute("users") public Page<User> users(@PageableDefault(size = 5) Pageable pageable) { return userManagement.findAll(pageable); }
我們只需要在方法的參數中直接定義一個pageable類型的參數,當Spring發現這個參數時,Spring會自動的根據request的參數來組裝該pageable對象,Spring支持的request參數如下: page,第幾頁,從0開始,預設為第0頁 size,每一頁的大小,預設為20 sort,排序相關的信息,以property,property(,ASC|DESC)的方式組織,例如sort=firstname&sort=lastname,desc表示在按firstname正序排列基礎上按lastname倒序排列 這樣,我們就可以通過url的參數來進行多樣化、個性化的查詢,而不需要為每一種情況來寫不同的方法了。 通過url來定製pageable很方便,但唯一的缺點是不太美觀,因此我們需要為pageable設置一個預設配置,這樣很多情況下我們都能夠通過一個簡潔的url來獲取信息了。 Spring提供了@PageableDefault幫助我們個性化的設置pageable的預設配置。例如@PageableDefault(value = 15, sort = { "id" }, direction = Sort.Direction.DESC)表示預設情況下我們按照id倒序排列,每一頁的大小為15。
spring.servlet.multipart.max-file-size=128KB spring.servlet.multipart.max-request-size=128KB spring.http.multipart.enabled=false
RestController
package api.restful; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import api.pojo.RestfulResponse; @RestController @RequestMapping("/upload") public class UploadRestController { private final static String FOLDER = "/tmp"; public UploadRestController() { } @PostMapping("/single") public RestfulResponse upload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { if (file.isEmpty()) { return new RestfulResponse(false, 0, "Please select a file to upload", ""); } try { byte[] bytes = file.getBytes(); Path path = Paths.get(FOLDER + "/" + file.getOriginalFilename()); Files.write(path, bytes); return new RestfulResponse(true, 0, "", path.toString()); } catch (Exception e) { return new RestfulResponse(false, 0, e.getMessage(), null); } } @PostMapping(value = "/group") public RestfulResponse group(@RequestParam("files") MultipartFile[] files) { List<String> filelist = new ArrayList<String>(); try { for (MultipartFile file : files) { File tmpfile = new File(FOLDER + "/" + file.getOriginalFilename()); file.transferTo(tmpfile); filelist.add(tmpfile.getPath()); } return new RestfulResponse(true, 0, null, filelist); } catch (Exception e) { return new RestfulResponse(false, 0, e.getMessage(), null); } } }
由於上傳檔案名可能存在空格等特殊字元,這裡使用UUID替代檔案名
@PostMapping(value = "/file") public RestfulResponse file(@RequestParam("file") MultipartFile[] files) { List<Object> filelist = new ArrayList<Object>(); try { for (MultipartFile file : files) { UUID uuid = UUID.randomUUID(); String filename = String.format("%s/%s.%s", folder, uuid.toString(), this.getExtensionName(filename)); File tmpfile = new File(filename); String filepath = tmpfile.getPath(); System.out.println(filepath); file.transferTo(tmpfile); filelist.add(tmpfile.toString()); } return new RestfulResponse(true, 0, null, filelist); } catch (Exception e) { return new RestfulResponse(false, 0, e.getMessage(), null); } } private String getExtensionName(String filename) { if ((filename != null) && (filename.length() > 0)) { int dot = filename.lastIndexOf('.'); if ((dot > -1) && (dot < (filename.length() - 1))) { return filename.substring(dot + 1); } } return filename; }