Spring Security(編寫restful風(fēng)格的接口)

用戶詳情請求

使用@PathVariable注解去綁定url中的參數(shù)

    @RequestMapping(value="user/{id}",method = RequestMethod.GET)
    public User getInfo(@PathVariable(required = false) String id) {
        User user=new User();
        user.setUsername("tom");
        return user;
    }

測試用例

    @Test
    public void whenGenInfoSuccess() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.username").value("tom"));
    }

需求:傳來的必須是數(shù)字

    @RequestMapping(value="user/{id:\\d+}",method = RequestMethod.GET)
    public User getInfo(@PathVariable(required = false) String id) {
        User user=new User();
        user.setUsername("tom");
        return user;
    }
    @Test
    public void whenGenInfoFail() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/a")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(MockMvcResultMatchers.status().is4xxClientError());
    }

需求:query接口不能將password字段返回給前端隐解,getInfo接口要將password字段返回給前端
解析:使用@JsonView

@Data
public class User {
    @JsonView(UserSimpleView.class)
    private String username;
    @JsonView(UserDetailView.class)
    private String password;
    
    public interface UserSimpleView{};
    
    public interface UserDetailView extends UserSimpleView{};
}
@RestController
public class UserController {
    
    
    @RequestMapping(value = "/user",method = RequestMethod.GET)
    @JsonView(User.UserSimpleView.class)
    public List<User> query(@RequestParam(required = false) String username,@PageableDefault(page = 1,size = 10,sort = "username,asc") Pageable pageable){
        System.out.println(pageable.getPageSize()+"---"+pageable.getPageNumber()+"---"+pageable.getSort());
        List<User> users=new ArrayList<User>(3);
        users.add(new User());
        users.add(new User());
        users.add(new User());
        return users;
    }
    @JsonView(User.UserDetailView.class)
    @RequestMapping(value="user/{id:\\d+}",method = RequestMethod.GET)
    public User getInfo(@PathVariable(required = false) String id) {
        User user=new User();
        user.setUsername("tom");
        return user;
    }
    
}

用戶創(chuàng)建請求

    @PostMapping
    public User createUser(User user) {
        System.out.println("user==>"+user);
        user.setId("1");
        return user;
    }
    @Test
    public void whenCreateSuccess() throws Exception {
        String content = "{\"username\":\"tom\",\"password\":null}";
        String res = mockMvc
                .perform(MockMvcRequestBuilders.post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
                        .content(content))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1)).andReturn().getResponse()
                .getContentAsString();
        System.out.println(res);
    }

發(fā)現(xiàn)controller類的參數(shù)User內(nèi)并沒有傳過來的值稿黍。
需要加一個@RequestBody

    @PostMapping
    public User createUser(@RequestBody User user) {
        System.out.println("user==>"+user);
        user.setId("1");
        return user;
    }

之前并沒有接觸過@RequestBody注解霸妹,網(wǎng)上查詢了一下該注解的作用https://blog.csdn.net/justry_deng/article/details/80972817
簡單的說就是:參數(shù)放在請求體中,必須用@RequestBody注解接收。

需求:處理日期類型的參數(shù)
(視頻上所說,由于現(xiàn)在前后端分離的情況阁吝,可能后臺一個接口會被不同的渠道調(diào)用棠耕,app余佛,網(wǎng)頁端。這些渠道可能顯示的格式不同窍荧,所以一般而言后端傳給前端會是時間戳格式,然后再由前端選擇顯示的格式恨憎。但我們現(xiàn)在并不是= =蕊退,而是傳格式化好了的時間,可以用@DateTimeFormat 和 @JsonFormat 注解憔恳,@DateTimeFormat 在RequestBody中不生效)

需求:校驗參數(shù)的合法性瓤荔,并處理校驗的結(jié)果
解析:使用@vaild注解和BindingResult注解

@Data
@ToString
public class User {
    @JsonView(UserSimpleView.class)
    private String id;
    
    @JsonView(UserSimpleView.class)
    private String username;
    
    @NotBlank(message = "密碼不能為空")
    @JsonView(UserDetailView.class)
    private String password;

    private Date birthDate;

    public interface UserSimpleView {
    };

    public interface UserDetailView extends UserSimpleView {
    };
}
    @PostMapping
    public User createUser(@Valid @RequestBody User user,BindingResult errors) {
        if(errors.hasErrors()) {
            errors.getAllErrors().stream().forEach(error-> System.out.println(error.getDefaultMessage()));
        }
        
        System.out.println("user==>"+user);
        user.setId("1");
        return user;
    }

(這里我使用的參數(shù)校驗和視頻上的略有出入,看我的實現(xiàn)可以看常用功能文章系列的參數(shù)校驗?zāi)且黄孔椤#?/p>

用戶修改請求

@Data
@ToString
public class User {
    @JsonView(UserSimpleView.class)
    private String id;
    
    @JsonView(UserSimpleView.class)
    private String username;
    
    @NotBlank(message = "密碼不能為空")
    @JsonView(UserDetailView.class)
    private String password;

    @Past(message = "生日必須是過去的時間")
    private Date birthDate;

    public interface UserSimpleView {
    };

    public interface UserDetailView extends UserSimpleView {
    };
}
    @PutMapping(value="/{id:\\d+}")
    public User updateUser(@Valid @RequestBody User user,BindingResult errors) {
        if(errors.hasErrors()) {
            errors.getAllErrors().stream().forEach(error-> System.out.println(error.getDefaultMessage()));
        }
        System.out.println("user==>"+user);
        user.setId("1");
        return user;
    }
    @Test
    public void whenUpdateSuccess() throws Exception {
        Date date=new Date(LocalDateTime.now().plusYears(1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        
        String content = "{\"id\":\"1\",\"username\":\"tom\",\"password\":null,\"birthDate\":"+date.getTime()+"}";
        String res = mockMvc
                .perform(MockMvcRequestBuilders.put("/user/1").contentType(MediaType.APPLICATION_JSON_UTF8)
                        .content(content))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1)).andReturn().getResponse()
                .getContentAsString();
        System.out.println(res);
    }

需求:自定義校驗注解

public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> {

    @Override
    public void initialize(MyConstraint constraintAnnotation) {
        System.out.println("MyConstraintValidator  init");
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        System.out.println("value==》"+value);
        // TODO 寫具體的校驗邏輯输硝,true驗證通過,false驗證不過
        return false;
    }

}
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyConstraint {
    String message() default "";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

}
    @MyConstraint(message = "自定義校驗不過")
    @JsonView(UserSimpleView.class)
    private String username;

服務(wù)器異常處理

spring boot的默認(rèn)異常處理機(jī)制是程梦,瀏覽器返回錯誤頁面点把,客戶端返回json數(shù)據(jù)。
1屿附、在src/main/resources下建立resources文件夾郎逃,然后再建error文件夾,再建立相應(yīng)的錯誤頁面挺份。如404.hmtl褒翰,500.html


image.png

多線程提高接口性能

使用swagger生成文檔

1、引入pom依賴

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

2匀泊、使用@EnableSwagger2開啟swagger

@SpringBootApplication
@EnableSwagger2
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3优训、使用注解
@Api注解:說明這個controller是干什么的

@Api("用戶服務(wù)")
public class UserController

@ApiOperation:說明這個方法是干什么的

    @ApiOperation(value = "用戶創(chuàng)建服務(wù)")
    @PostMapping
    public User createUser(@Valid @RequestBody User user,BindingResult errors)

@ApiModelProperty :參數(shù)是對象時,說明對象的屬性

    @ApiModelProperty("用戶名")
    @JsonView(UserSimpleView.class)
    private String username;
    
    @ApiModelProperty("用戶密碼")
    @NotBlank(message = "密碼不能為空")
    @JsonView(UserDetailView.class)
    private String password;

    @ApiModelProperty("用戶生日")
    @Past(message = "生日必須是過去的時間")
    private Date birthDate;

@ApiParam:參數(shù)是單獨的一個時各聘,說明揣非。

public List<User> query(@ApiParam("用戶名")@RequestParam(required = false) String username,@PageableDefault(page = 1,size = 10,sort = "username,asc") Pageable pageable){

參考鏈接:http://www.reibang.com/p/a66cf3acd29a

使用wiremock偽造rest服務(wù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伦吠,隨后出現(xiàn)的幾起案子妆兑,更是在濱河造成了極大的恐慌,老刑警劉巖毛仪,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搁嗓,死亡現(xiàn)場離奇詭異,居然都是意外死亡箱靴,警方通過查閱死者的電腦和手機(jī)腺逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衡怀,“玉大人棍矛,你說我怎么就攤上這事安疗。” “怎么了够委?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵荐类,是天一觀的道長。 經(jīng)常有香客問我茁帽,道長玉罐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任潘拨,我火速辦了婚禮吊输,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铁追。我一直安慰自己季蚂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布琅束。 她就那樣靜靜地躺著扭屁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狰闪。 梳的紋絲不亂的頭發(fā)上疯搅,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機(jī)與錄音埋泵,去河邊找鬼幔欧。 笑死,一個胖子當(dāng)著我的面吹牛丽声,可吹牛的內(nèi)容都是我干的礁蔗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼雁社,長吁一口氣:“原來是場噩夢啊……” “哼浴井!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起霉撵,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤磺浙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后徒坡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撕氧,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年喇完,在試婚紗的時候發(fā)現(xiàn)自己被綠了伦泥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖不脯,靈堂內(nèi)的尸體忽然破棺而出府怯,到底是詐尸還是另有隱情,我是刑警寧澤防楷,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布牺丙,位于F島的核電站,受9級特大地震影響复局,放射性物質(zhì)發(fā)生泄漏赘被。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一肖揣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浮入,春花似錦龙优、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至易迹,卻和暖如春宰衙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背睹欲。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工供炼, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窘疮。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓嘱巾,卻偏偏與公主長得像胖烛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359