从零构建后端项目-创建基础类

这篇具有很好参考价值的文章主要介绍了从零构建后端项目-创建基础类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

创建自定义异常类

封装Web返回对象

利用Swagger搭建REST API

配置Swagger

一、添加依赖库

二、创建Swagger配置类

三、编写测试Web接口

四、修改全局的配置文件

五、测试Web接口

配置后端验证功能

一、添加依赖

二、创建Form类 

三、修改sayHello()方法

四、执行测试

抵御即跨站脚本(XSS)攻击

一、XSS攻击的危害

二、导入依赖库

三、定义请求包装类

四、创建过滤器,把所有请求对象传入包装类

五、给主类添加注解

六、测试拦截XSS脚本


创建自定义异常类

        因为后台Java项目是Web工程,所以有异常消息,我们要在原有异常消息的基础之上,封装状态码,所以需要我们自己创建一个异常类。 

        自定义异常类继承的父类,我没有选择Exception。因为Exception类型的异常,我们必须要手动显式处理,要么上抛,要么捕获。我希望我定义的异常采用既可以采用显式处理,也可以隐式处理,所以我选择继承RuntimeException这个父类。RuntimeException类型的异常可以被虚拟隐式处理,这样就省去了我们很多手动处理异常的麻烦。 

        1. 创建 com.example.emos.wx.exception 包

        2. 创建EmosException类

package com.example.emos.wx.exception; 
import lombok.Data; 
@Data
public class EmosException extends RuntimeException{ 
    private String msg; 
    private int code = 500; 
    public EmosException(String msg) { 
        super(msg);
        this.msg = msg;
    }
    public EmosException(String msg, Throwable e) {
        super(msg, e);
        this.msg = msg;
    }
    public EmosException(String msg, int code) {
        super(msg);
        this.msg = msg;
        this.code = code;
    }
    public EmosException(String msg, int code, Throwable e) {
        super(msg, e);
        this.msg = msg;
        this.code = code;
    }
}

封装Web返回对象

        虽然SpringMVC的Controller可以自动把对象转换成JSON返回给客户端,但是我们需要制定一个统一的标准,保证所有Controller返回的数据格式一致。最简便的办法就是定义封装类,来统一封装返回给客户端的数据。 

        1. 修改 pom.xml 文件,添加依赖库。 Apache 的 httpcomponents 库里面的 HttpStatus 类封装了很多状态码,所以我们在Web返回对象中封装状态吗,可以用到这些状态码。添加依赖后Maven重新加载项目。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.13</version>
</dependency>

        2. 创建 com.example.emos.wx.common.util 包,然后创建 R 类

        3. 代码

package com.example.emos.wx.common.util; 
import org.apache.http.HttpStatus; 
import java.util.HashMap; 
import java.util.Map; 

public class R extends HashMap<String, Object> { 
    public R() { 
        put("code", HttpStatus.SC_OK);
        put("msg", "success");
    }
    public static R error() {
        return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
    }
    public static R error(String msg) {
        return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
    }
    public static R error(int code, String msg) {
        R r = new R();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }
    public static R ok(String msg) {
        R r = new R();
        r.put("msg", msg);
        return r;
    }
    public static R ok(Map<String, Object> map) {
        R r = new R();
        r.putAll(map);
        return r;
    }
    public static R ok() {
        return new R();
    }
    public R put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

利用Swagger搭建REST API

        开发前后端分离架构的项目,往往调试后端Web接口需要用到POSTMAN工具。虽然POSTMAN工具的功能非常强大,但是请求参数很多的情况下,我们手写这些参数和数据还是非常麻烦的。因此我们需要一个调试后端Web接口更加简便的方法。恰好Swagger提供了REST API调用方式,我们不需要借助任何工具的情况下,访问Swagger页面,就可以对Web接口进行调用和调试,这种调试方式的效率要远超POSTMAN软件。

配置Swagger

1. (ApiInfoBuilder)定义Swagger页面基本信息

2. (ApiSelectorBuilder)哪些类中的方法会出现在Swagger上面

3. 开启对JWT的支持

        ·List<ApiKey>: 用户需要输入什么参数

        ·AuthorizationScope[]: JWT认证在Swagger中的作用域

        ·List<SecurityReference>: 令牌的作用域

        ·List<SecurityContext>: 令牌上下文

        ·Docket

把配置信息给Spring

一、添加依赖库

        在 pom.xml 文件中添加Swagger依赖库,这里我们使用的是Swagger2版本,在UI方面,比 Swagger1版本要好看很多。 

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

二、创建Swagger配置类

在 com.example.emos.wx.config 包中创建 SwaggerConfig 类

package com.example.emos.wx.config; 
import io.swagger.annotations.ApiOperation; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 
import springfox.documentation.builders.ApiInfoBuilder; 
import springfox.documentation.builders.PathSelectors; 
import springfox.documentation.builders.RequestHandlerSelectors; 
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2);
        // ApiInfoBuilder 用于在Swagger界面上添加各种信息
        ApiInfoBuilder builder = new ApiInfoBuilder();
        builder.title("EMOS在线办公系统");
        ApiInfo apiInfo = builder.build();
        docket.apiInfo(apiInfo);
        // ApiSelectorBuilder 用来设置哪些类中的方法会生成到REST API中
        ApiSelectorBuilder selectorBuilder = docket.select();
        selectorBuilder.paths(PathSelectors.any()); //所有包下的类
        //使用@ApiOperation的方法会被提取到REST API中
 selectorBuilder.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class));
        docket = selectorBuilder.build();
        /*
         * 下面的语句是开启对JWT的支持,当用户用Swagger调用受JWT认证保护的方法,
         * 必须要先提交参数(例如令牌)
         */
        //存储用户必须提交的参数
        List<ApiKey> apikey = new ArrayList();
        //规定用户需要输入什么参数
        apikey.add(new ApiKey("token", "token", "header"));
        docket.securitySchemes(apikey);
        //如果用户JWT认证通过,则在Swagger中全局有效
        AuthorizationScope scope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] scopeArray = {scope};
        //存储令牌和作用域
        SecurityReference reference = new SecurityReference("token", scopeArray);
        List refList = new ArrayList();
        refList.add(reference);
        SecurityContext context =
SecurityContext.builder().securityReferences(refList).build();
        List cxtList = new ArrayList();
        cxtList.add(context);
        docket.securityContexts(cxtList);
        return docket;
    }
}

三、编写测试Web接口

在 com.example.emos.wx.controller 包中创建 TestController 类。

package com.example.emos.wx.controller; 
import com.example.emos.wx.common.util.R; 
import io.swagger.annotations.Api; 
import io.swagger.annotations.ApiOperation; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 

@RestController
@RequestMapping("/test")
@Api("测试Web接口")
public class TestController {
    @GetMapping("/sayHello")
    @ApiOperation("最简单的测试方法")
    public R sayHello(){
        return R.ok().put("message","HelloWorld");
    }
}

四、修改全局的配置文件

不修改会导致错误,就下面出现的问题。

because the return value of “springfox.documentation.spi.service.contexts.Orderings.patternsCondition(springfox.documentation.RequestHandler)” is null

在application.yml文件中增加配置,配置内容如下:

spring:
  mvc:
    pathmatch:
      matching-strategy: ant-path-matcher

        如Spring Boot 2.6发行说明中所述,您可以通过在application.properties文件中将Spring.mvc.pathmatch.matching-strategy设置为ant path matcher来恢复Springfox假定将使用的配置。请注意,只有在不使用Spring Boot的执行器时,此功能才起作用。无论配置的匹配策略如何,执行器始终使用基于路径模式的解析。如果您想在Spring Boot 2.6及更高版本中将其与执行器一起使用,则需要对Springfox进行更改。

        因为在springboot2.6之后,将springmvc的默认匹配策略修改为了PathPatternParser,需要将其修改为AntPathMatcher就可以解决问题 

五、测试Web接口

        打开浏览器,访问 http://127.0.0.1:8080/emos-wx-api/swagger-ui.html

配置后端验证功能

库:Validation

创建Form类

·类声明要添加 @ApiModel【因为要出现在Swagger页面里】

·属性声明要添加 @ApiModelProperty【因为要出现在Swagger页面里】

·属性声明要添加验证注解 @NotNull @NotBlank @Min @Max @Range @Pattern

验证数据要使用 @Valid 注解

        当用户提交请求的时候,SpringBoot项目就会把提交的数据封装到Form对象里面。同时执行后端的验证,如果数据满足要求,那么Web方法就可以正常的执行。如果不满足要求就会抛出异常,返回错误信息给客户端。

        对于客户端提交表单或者Ajax中的数据,后端的Controller必须先要做验证,然后才能使用这些数据。既然要验证数据,那么不妨我们来使用一下 Validation 库。

一、添加依赖

在 pom.xml 文件中添加依赖,然后让Maven加载依赖库。 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、创建Form类 

        validation 库在做后端验证的时候,要求必须用封装类(Form类)来保存客户端提交的数据, 然后在封装类中,我们可以定义验证的规则, validation 会执行这些规则,帮我们验证客户端 提交的数据。 

        我们为之前的 TestController 里面的 sayHello() 方法设置一个Form类,接受客户端提交的 name 数据。我们在 com.example.emos.wx.controller.form 包里面创建 TestSayHelloForm 类。 

package com.example.emos.wx.controller.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

@ApiModel
@Data
public class TestSayHelloForm {
    @NotBlank
    @Pattern(regexp = "^[\\u4e00-\\u9fa5]{2,15}$")
    @ApiModelProperty("姓名")
    private String name;
}

三、修改sayHello()方法

package com.example.emos.wx.controller; 
import com.example.emos.wx.common.util.R; 
import com.example.emos.wx.controller.form.TestSayHelloForm; 
import io.swagger.annotations.Api; 
import io.swagger.annotations.ApiOperation; 
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; 
import javax.validation.Validation; 

@RestController
@RequestMapping("/test")
@Api("测试Web接口")
public class TestController {
    @PostMapping("/sayHello")
    @ApiOperation("最简单的测试方法")
    public R sayHello(@Valid @RequestBody TestSayHelloForm form){
        return R.ok().put("message","Hello,"+form.getName());
    }
}

四、执行测试

        打开浏览器,访问 http://127.0.0.1:8080/emos-wx-api/swagger-ui.html

抵御即跨站脚本(XSS)攻击

库:Hutool

对Http请求中的数据转义

·设置过滤器

·覆盖Http请求的方法

        HttpServletRequest是接口,各家服务器厂商会实现它。

        如果直接继承各厂商的请求父类,那么我们的程序就跟厂商绑定在一起。

        HttpServletRequestWrapper类使用了装饰器模式,装饰器封装了厂商的HttpServletRequest,只需要覆盖Wrapper类的方法,就能做到覆盖厂商请求对象里方法。

        创建过滤器,把Request对象传入Wrapper对象。


getInputStream方法

        非常重要。SpringMVC框架就是通过这个方法,从请求里面提取客户端提交的数据,然后把这些数据封装到Form对象里面。如果我们不对 getInputStream 方法读取的数据做转义,那么后端项目就不具备抵御跨站脚本攻击的能力。

Java不支持原生JSON格式


一、XSS攻击的危害

        XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种 内容。 

        例如用户在发帖或者注册的时候,在文本框中输入 <script>alert('xss')</script> ,这段代码 如果不经过转义处理,而直接保存到数据库。将来视图层渲染HTML的时候,把这段代码输出到页面上,那么 <script> 标签的内容就会被执行。通常情况下,我们登录到某个网站。如果网站使用 HttpSession 保存登录凭证,那么SessionId 会以 Cookie 的形式保存在浏览器上。如果黑客在这个网页发帖的时候,填写的JavaScript 代码是用来获取 Cookie 内容的,并且把 Cookie 内容通过Ajax发送给黑客自己的电脑。于是只要有人在这个网站上浏览黑客发的帖子,那么视图层渲染HTML页面,就会执行注入的XSS脚本,于是你的 Cookie 信息就泄露了。黑客在自己的电脑上构建出 Cookie ,就可以冒充已经登录的用户。 

        即便很多网站使用了JWT,登录凭证( Token令牌 )是存储在浏览器上面的。所以用XSS脚本可以轻松的从Storage中提取出 Token ,黑客依然可以轻松的冒充已经登录的用户。所以避免XSS攻击最有效的办法就是对用户输入的数据进行转义,然后存储到数据库里面。等到视图层渲染HTML页面的时候。转义后的文字是不会被当做JavaScript执行的,这就可以抵御XSS攻击。

二、导入依赖库

        因为 Hutool 工具包带有XSS转义的工具类,所以我们要导入 Hutool ,然后利用 Servlet 规范提供的请求包装类,定义数据转义功能。 

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.4.0</version>
</dependency>

三、定义请求包装类

        我们平时写Web项目遇到的 HttpServletRequest ,它其实是个接口。如果我们想要重新定义请求类,扩展这个接口是最不应该的。因为 HttpServletRequest 接口中抽象方法太多了,我们逐一实现起来太耗费时间。所以我们应该挑选一个简单一点的自定义请求类的方式。那就是继承HttpServletRequestWrapper 父类。

        JavaEE只是一个标准,具体的实现由各家应用服务器厂商来完成。比如说 Tomcat 在实现Servlet 规范的时候,就自定义了 HttpServletRequest 接口的实现类。同时JavaEE规范还定义了 HttpServletRequestWrapper ,这个类是请求类的包装类,用上了装饰器模式。不得不说这里用到的设计模式真的非常棒,无论各家应用服务器厂商怎么去实现 HttpServletRequest 接口,用户想要自定义请求,只需要继承 HttpServletRequestWrapper ,对应覆盖某个方法即可,然后把请求传入请求包装类,装饰器模式就会替代请求对象中对应的某个方法。用户的代码和服务器厂商的代码完全解耦,我们不用关心 HttpServletRequest 接口是怎么实现的,借助于包装类我们可以随意修改请求中的方法。同学们,如此优雅的代码设计,有时间你真该认真学习设计模式。

package com.example.emos.wx.config.xss; 
import cn.hutool.core.util.StrUtil; 
import cn.hutool.http.HtmlUtil; 
import cn.hutool.json.JSONUtil; 
import javax.servlet.ReadListener; 
import javax.servlet.ServletInputStream; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }
    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                if (!StrUtil.hasEmpty(value)) {
                    value = HtmlUtil.filter(value);
                }
                values[i] = value;
            }
        }
        return values;
    }
    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> parameters = super.getParameterMap();
        Map<String, String[]> map = new LinkedHashMap<>();
        if (parameters != null) {
            for (String key : parameters.keySet()) {
                String[] values = parameters.get(key);
                for (int i = 0; i < values.length; i++) {
                    String value = values[i];
                    if (!StrUtil.hasEmpty(value)) {
                        value = HtmlUtil.filter(value);
                    }
                    values[i] = value;
                }
                map.put(key, values);
            }
        }
        return map;
    }
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        InputStream in = super.getInputStream();
        StringBuffer body = new StringBuffer();
        InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
        BufferedReader buffer = new BufferedReader(reader);
        String line = buffer.readLine();
        while (line != null) {
            body.append(line);
            line = buffer.readLine();
        }
        buffer.close();
        reader.close();
        in.close();
        Map<String, Object> map = JSONUtil.parseObj(body.toString());
        Map<String, Object> resultMap = new HashMap(map.size());
        for (String key : map.keySet()) {
            Object val = map.get(key);
            if (map.get(key) instanceof String) {
                resultMap.put(key, HtmlUtil.filter(val.toString()));
            } else {
                resultMap.put(key, val);
            }
        }
        String str = JSONUtil.toJsonStr(resultMap);
        final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bain.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener listener) {
            }
        };
    }
}

四、创建过滤器,把所有请求对象传入包装类

        为了让刚刚定义的包装类生效,我们还要在 com.example.emos.wx.config.xss 中创建XssFilter 过滤器。过滤器拦截所有请求,然后把请求传入包装类,这样包装类就能覆盖所有请求的参数方法,用户从请求中获得数据,全都经过转义。 

package com.example.emos.wx.config.xss;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class XssFilter implements Filter {

    public void init(FilterConfig config) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper( (HttpServletRequest) request);
        chain.doFilter(xssRequest, response);
    }

    @Override
    public void destroy() {
    }
}

五、给主类添加注解

        给SpringBoot主类添加 @ServletComponentScan 注解。

六、测试拦截XSS脚本

        1. 把 TestSayHelloForm 中的正则表达式验证给去掉,因为 name 字段只可以是中文,所以无法接收XSS脚本。 

        2. 在Swagger中,执行 sayHello() 方法,向name属性传入<script>HelloWorld</script> ,然后观察返回的结果。文章来源地址https://www.toymoban.com/news/detail-489834.html

到了这里,关于从零构建后端项目-创建基础类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux :: 【基础指令篇 :: 文件及目录操作:(4)】:: mkdir :: 创建目录:指定路径单个目录创建及一次性创建多级目录

    前言:本篇是 Linux 基本操作篇章的内容! 笔者使用的环境是基于腾讯云服务器:CentOS 7.6 64bit。 学习集: C++ 入门到入土!!!学习合集 Linux 从命令到网络再到内核!学习合集 目录索引: 1. 基本语法及功能 2. 基本使用示例 - - 2.1 当前目录下创建指定新目录 - - 2.2 指定目录下

    2024年02月06日
    浏览(45)
  • 从零开始创建Unity自定义包Package:一步一步实现您的功能

    内容将会持续更新,有错误的地方欢迎指正,谢谢!   从零开始创建Unity自定义包Package:一步一步实现您的功能       TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 TechX —— 心探索、心进取! 助力快速掌握 Package 自定义包的实

    2024年02月04日
    浏览(38)
  • nextjs系列教程(二):项目创建及目录结构

    1. 使用 create-next-app创建新的 Next.js 应用程序,它会自动为你设置所有内容。 2. 如果你希望使用 TypeScript 开发项目,可以通过 --typescript 参数创建 TypeScript 项目 3. 创建过程中会提示选择项目配置,截图如下 项目名称,这里输入react_next_pro。 项目是否需要使用Typescript。 项目是

    2024年02月09日
    浏览(37)
  • Rust图形界面:从零开始创建eGUi项目

    egui系列:初步 首先,用cargo创建一个新项目,并添加eframe 尽管默认创建的项目只实现了输出Hello world功能,但添加了eframe库,所以下载需要一点时间。 创建成功后,直接把下面的代码写入main.rs文件中,这些代码来自egui的hello_world示例。 然后运行cargo run,结果如下所示 在e

    2024年02月01日
    浏览(47)
  • JAVA-服务器搭建-创建web后端项目

       

    2024年04月22日
    浏览(58)
  • VitePress-01-从零开始的项目创建(npm版)

    本文介绍一下 VitePress 的项目创建的步骤。 主要用到的命令工具是 npm 。 本文的操作步骤是 从无到有 的创建一个完整的基本的【VitePress】项目。 根据官方文档的介绍,截止本文发稿时,需要使用 node.js 18+ 的版本。 可以使用 node -v 的命令查看版本。 如果不满足要求的,可以

    2024年01月20日
    浏览(33)
  • Python Django 零基础从零到一部署服务,Hello Django!全文件夹目录和核心代码!

    在这篇文章中,我将手把手地教你如何从零开始部署一个使用Django框架的Python服务。无论你是一个刚开始接触开发的新手,还是一个有经验的开发者想要快速了解Django,这篇教程都会为你提供一条清晰的路径。我们将从环境搭建开始,一步一步地创建一个可以处理GET和POST请求

    2024年02月12日
    浏览(37)
  • Linux rm命令详解,Linux删除文件目录(非常详细)从零基础入门到精通,看完这一篇就够了。

    一、常用操作 1. 删除文件 2. 删除目录 二、其他操作 作用:删除文件或目录 参数: -f 直接删除,不需要确认。 -r 递归删除(用来删除目录) -i 删除前逐一询问。 -v 显示步骤 -d 只删除空目录 1)rm 后面直接跟文件名,可以删除文件,删除前会询问是否删除(y确认,n取消)

    2024年02月06日
    浏览(49)
  • 个人博客-SpringBoot+Vue3项目实战(3)Springboot+Mybatis创建后端项目

    🧨🧨🧨 大家好,我是搞前端的半夏 🧑,一个热爱写文的前端工程师 💻. 如果喜欢我的文章,可以关注 ➕ 点赞 👍 一起学习交流前端,成为更优秀的工程师~ 更多故事—点我探索新世界! 🧨🧨🧨 本专栏以搭建一个个人博客为目标,从前后端开发的开发,云服务的配置

    2023年04月10日
    浏览(39)
  • Flask框架小程序后端分离开发学习笔记《2》构建基础的HTTP服务器

    Flask是使用python的后端,由于小程序需要后端开发,遂学习一下后端开发。本节提供一个构建简单的本地服务器的代码,仔细看注释,学习每一步的流程,理解服务器接收请求,回复响应的基本原理。 代码效果,运行之后,在浏览器输入:localhost:2000 总结 1.导入socket库:这个库

    2024年01月18日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包