前后端分离项目总结

  1. 前端环境准备

1、Node.js下载
node.js下载地址
下载方式可参考博客
Node.js最新最详细安装教程(2020)

2、安装vue-cli
参考文档

npm install -g @vue/cli

安装成功后,运行cmd输入vue -V查看版本,此时有可能提示无法使用该命令,可参考该博客

3、以上全部环境安装后,即可创建vue项目
以管理员身份运行cmd,
输入命令vue create “项目名称”
然后按照下图方式进行选择
在这里插入图片描述
然后根据指定操作运行即可 npm run serve
环境准备完毕,即可开始写代码

用idea打开vue项目
添加如下操作,即可用idea运行vue项目
在这里插入图片描述

  1. 前端编写

项目环境准备完后开始写前端代码。
可参考Element Plus编写前端样式。
首先引入element-plus样式

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(ElementPlus)

以组件的形式拼接页面
在这里插入图片描述
导入request.js文件,和后端进行数据交互使用

import axios from 'axios'

const request = axios.create({
    timeout: 5000
})

// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';

    // config.headers['token'] = user.token;  // 设置请求头
    return config
}, error => {
    return Promise.reject(error)
});

// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
    response => {
        let res = response.data;
        // 如果是返回的文件
        if (response.config.responseType === 'blob') {
            return res
        }
        // 兼容服务端返回的字符串数据
        if (typeof res === 'string') {
            res = res ? JSON.parse(res) : res
        }
        return res;
    },
    error => {
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)


export default request


//在需要与后端交互的操作中使用request,这里request必须与导入request.js一致,否则报错。
//这里url为后端接口,也是整个前后端项目的核心所在,前后端交互只需使用相应的接口即可
save(){
        request.post("http://localhost:9091/user",this.form).then(res =>{
           console.log(res)
        })
      this.dialogVisible=false
    }

后:

1、技术选型
vue+springboot+ElementUI+shiro
及支付宝支付接入

2、功能概述
1、登录及注册功能:
在这里插入图片描述
在这里插入图片描述
2、信息管理
在这里插入图片描述
可实现增删改查操作及分页功能

3、书籍管理
在这里插入图片描述
可进行增删改查操作及书籍购买功能

4、我的商品在这里插入图片描述
记录已购买商品,可删除购买记录。

3、各种坑的记录

3.1、支付宝接入

@Controller
@CrossOrigin
@RequestMapping("/pay")
public class PayController {
    @ResponseBody
    @GetMapping
    public String pay(@RequestParam String OutTradeNo,@RequestParam String TotalAmount,@RequestParam String SubjectQx) throws AlipayApiException {
        AlipayClient alipayClient = new
              DefaultAlipayClient("https://openapi.alipaydev.com/gateway.do", "2021000118622319", "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDjV5nkoMfeh6ZW6f3DvuIYnQLfkGEBpi7ZMkuLgZ5MVeAdybEJLSuB2m5cvS8Ba2b90p6OiUv4apCoeaU/JeaYzXV6JVRWtK2RkZ/YrdwyTcSE3QIk8OsnkeuTbtiS71pE9gKDxPvKSflrl5qwdyBxjTZMCmbnZX9NYIahbSuFrSAzWMa4yRM5aTzyWAgIDFn/Bs8LDzCQb9Xa1XZH2UM5VnM5Itw8OErsNDHGA4tuMLgtQYQD4pvDx+EujzOECFCSutlTJdEOsLhMlzwX/NPgFNuv1ipamghCnlfE0lKGuCTWLtmpDgJLM98PjX7gGmhXcveYpX5AemxDGLn6FClfAgMBAAECggEBAIs9HQE9RAzUEhnLaGQaJgojKB5bJD7JVIosVr6T3astMX2tCSPwqWP3r35XVFHPQR4WgIwWJRR52C2Hi6D4ipptxBTShiwwrtmoUjl4ipO4s7MYVXbgo3Xx1lHPIxAjTqtL7VBdNkW4Nu4hxVltLM6/SVEbUdlJfcWbZ/m4jl5o+fmXVw+lrnmfb7Fn/CAouT4csneEIjPfHsFyHbEIbok0v60GaehXk/b7zzWRDcBwJcmZbIHmh2hkWq1fZJwaqxAVtpGn4hjpy5n6Uep1GxL6/bSFkhOIT8yoctjfYgzsIIOBCB6sEbMHKWHzCJfGvOSqL/Oqy3HN+b+OV1KEMEkCgYEA8vjmUNz662VHs0mmeDzGovtyzyIWlBl4u8zdcCRFwG/Z7tz9aA7sCgv0T3+JWeahY248TiagyFxFP0BQHotumxJYhHR+Jll0GYWgXuLpegjf8642x4Ty8W2dPREdPBwbNsmX3Skcn5zLNkgIPjpxuTUXpTqDJPRorjVqLjP47P0CgYEA74gotzZfSfK4PNUhSqhI0yDnX5hqTEUOfd7YBOTzkfs7UTEnGYfCDNRJQhFpe0RWj3s1uDTBI2IG4GWdEnyofEFvsF0kye9loF3iMbcP6O7ppLeF7APLOvMuwpCJ2+xhuL07tysPH3o2p4j1KTWzRF3chsM312b8y0cWkbzwLIsCgYB80ENwErSLK9HzVchAR+g6XTUTFo3GsncE8i5mpxt1yX+IZtl+FPxIBPARzpA+MG2DaGNuOgWqJ0wjO+RsbG/7FSeHk1giVx1+5tgFJkeNuvVgdoQJZlBumUKG1j3QXRfVwyVSJQZhL+hsEAC8BsXYwF9PL4mi+DK2GxZaebRL+QKBgHEhZOGLW5wIeD27B9tD+glFjCHZUbMuFncajfpZzDRRbSWeynHDbcIzbVo38RLYJu3jam7S87lrbgYD2BjIKaduHHs2ss5xNBV24gNLC8efN1ilmSnsbMst2hLow0PMtCbVsWOEgcMDLNcZ13icNUv/7Mz1XOVubczwiVdR3jmbAoGBAJ/grdLCK32p3rRykJ7ozDt0H/USZWBcarNI3+5pONBqyzASP0Y4mXhscsFczxGZhC2QZaJalWo5zhSOAvbTirwWZxihG347AIrpG/yPBKsBEKBozO4FzSYmPkGaNeqTPncWYD/hsodSGvYvOe8/yVeIWwPZnMVwIXGMKZPvdfDS", "json", "utf-8",
                "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkA452+NCGejZNdcBT0T1mSIgYTkdNKvR4NbI0Dfv5fFKK" +
                        "wJzu5uTQMUVWtHIWVbin7HvHWte8c5sJitPzGlUhLMaasnYCTxLW1m5sOcjbKfWg5tPqcOzMFcM5ayfu6eb1QKjc2NJuhB58FP/es4UHGW1W" +
                        "kxNP/BkMvVVB0GU9D63uBa2ZPKvg5iwd9FMlvMOVZOLhAf6Yb1zFa+mYYnSlBTSiI4TjaXPfE0mEoCfgpjX4w1Uopvf1rmQCfm3jY3MFIkwo" +
                        "K0TEsGapxEJucmRT9IXD1djJ+rqoflGy77Ff232M9ga57d/VD4EXFI/wz2FEffuBfWWY6zqBIFbimpBJQIDAQAB", "RSA2");
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(OutTradeNo);//流水号
        model.setSubject(SubjectQx);//订单标题
        model.setTotalAmount(TotalAmount);//订单总金额
        model.setQuitUrl("http://localhost:8080/myproduct");
        request.setNotifyUrl("http://9g73zd.natappfree.cc/notify");
        request.setReturnUrl("http://localhost:8080/myproduct");
        request.setBizModel(model);
        String form = alipayClient.pageExecute(request).getBody();
        return form;
    }

}

这里request.setNotifyUrl所请求的url必须为外网所能能够访问到的,采用内网穿透实现
在这里插入图片描述
具体操作可借鉴NATAPP

PayComfirmController
用于接收支付结果,将支付结果等数据插入数据库

package com.example.springboot.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.springboot.common.Result;
import com.example.springboot.mapper.TradeMessageMapper;
import com.example.springboot.pojo.TradeMessage;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Controller
@CrossOrigin
public class PayConfirmController {

    @Resource
    TradeMessageMapper tradeMessageMapper;

    @ResponseBody
    @RequestMapping("/notify")
    public void notfiyPay (HttpServletRequest request) throws AlipayApiException {
        Map<String,String> stringStringMap = convertRequestParamsToMap(request) ;
        boolean signVerified = AlipaySignature.rsaCheckV1(stringStringMap,"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkA452+NCGejZNdcBT0T1mSIgYTkdNKvR4NbI0Dfv5fFKKwJzu5uTQMUVWtHIWVbin7HvHWte8c5sJitPzGlUhLMaasnYCTxLW1m5sOcjbKfWg5tPqcOzMFcM5ayfu6eb1QKjc2NJuhB58FP/es4UHGW1WkxNP/BkMvVVB0GU9D63uBa2ZPKvg5iwd9FMlvMOVZOLhAf6Yb1zFa+mYYnSlBTSiI4TjaXPfE0mEoCfgpjX4w1Uopvf1rmQCfm3jY3MFIkwoK0TEsGapxEJucmRT9IXD1djJ+rqoflGy77Ff232M9ga57d/VD4EXFI/wz2FEffuBfWWY6zqBIFbimpBJQIDAQAB","utf-8","RSA2");
        if(signVerified)
        {
            String trade_no=stringStringMap.get("trade_no");
            String date=stringStringMap.get("gmt_payment");
            String trade_status=stringStringMap.get("trade_status");
            String out_trade_no=stringStringMap.get("out_trade_no");
            TradeMessage tradeMessage=new TradeMessage(trade_no,date,trade_status,out_trade_no);
            tradeMessageMapper.insert(tradeMessage);
           // System.out.println(stringStringMap);
        }
    }

    @ResponseBody
    @GetMapping("/confirmTrade/{date}")
    public Result<?> confirmTrade(@PathVariable String date)
    {
        LambdaQueryWrapper<TradeMessage> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(TradeMessage::getOutTradeNo,date);
        TradeMessage tradeMessage=tradeMessageMapper.selectOne(wrapper);
        //System.out.println(tradeMessage);
        return Result.success(tradeMessage);
    }
    //将request中请求转变为map
    private static Map<String,String> convertRequestParamsToMap(HttpServletRequest request)
    {
        Map<String,String> retMap = new HashMap<String,String>();
        Set<Map.Entry<String,String[]>> entrySet = request.getParameterMap().entrySet();
        for(Map.Entry<String,String[ ]> entry : entrySet)
        {
            String name = entry.getKey();
            String[ ] values = entry.getValue( );
            int valLen = values.length;
            if (valLen == 1)
            {
              retMap.put(name,values[0]);
            } else if (valLen > 1)
            {
                StringBuilder sb = new StringBuilder();
                for(String val : values)
                {
                   sb.append("," ).append (val);
                }
            retMap.put(name,sb.toString().substring(1));
            }
            else {
            retMap.put(name,"");
             }
         }
        return retMap;
    }
}

整个支付逻辑:
1、确定按钮:调用接口“/pay”,传入前端参数params: { OutTradeNo: date, TotalAmount: this.formBook.totalPrice, SubjectQx: this.formBook.productName }
2、支付成功后,进入异步请求,用于接收支付结果状态成功或失败 “/notify”,将数据插入数据库中以便后续取出作为判断依据。

3、接下来请求 “/confirmTrade/{date}”,用于取出支付状态,判断支付是否成功,成功则进入下一步,否则失败

4、若第三步成功,则可请求“/purchase”,将所购买的书籍插入到数据库中,至此,整个支付流程才算成功

注意前端逻辑代码编写:

 saveBook(){
                //购买中的确定按钮
                //在此添加支付宝确认功能,返回参数若为支付成功,即可进入下一步操作,插入数据库
                /*注意,这里的request请求后台之后,后台确实可以返回数据,但是不会自动跳转到指定的url
                * ,其作用就是单纯的对数据进行处理。比如后台通过数据处理后,想要把数据呈现到前端时,必须让它
                * 主动跳转
                * */
                //const date=1632847324588
               const date=new Date().getTime()

                console.log(date)
                request.get("http://localhost:9091/pay",
                    {
                         params: {
                             OutTradeNo: date,
                             TotalAmount: this.formBook.totalPrice,
                             SubjectQx: this.formBook.productName
                         }
                    }).then(
                    //这里url采用拼接的方式进行请求
                    console.log(date),
                   window.location.href='http://localhost:9091/pay?OutTradeNo='+date+'&TotalAmount='+this.formBook.totalPrice+'&SubjectQx='+this.formBook.productName
                )
                //嵌套request无法请求问题
               request.get("http://localhost:9091/confirmTrade/"+date).then(res =>{
                    console.log(res)
                   this.flagOfPay=res.data.tradeStatus
                })
                if(this.flagOfPay === "TRADE_SUCCESS")
                {
                    console.log("进入成功")
                    request.post("http://localhost:9091/purchase",this.formBook).then(res => {
                        console.log("方法执行成功")
                        if(res.code === '0'){
                            this.$message({
                                type: "success",
                                message: "购买成功"
                            })
                        }
                        else{
                            this.$message({
                                type: "error",
                                message: res.msg
                            })
                        }
                    })
                }
                else
                {
                    this.$message({
                        type:"error",
                        message:"支付失败"
                    })
                }
                this.dialogVisibleBook=false
                this.formBook={}//不能使用this.form 否则会出现第二次点击购买时无法弹出页面
            }

3.2 shiro框架接入
报302错误,屏蔽options请求、
可参考博客解决权限验证提示没有认证(Authentation)的问题
前后端分离时后端shiro权限认证
注解不产生作用可能没有引入aop,可参考前后端分离Shiro未执行授权方法解决办法

源代码地址

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio是一个集成开环境(IDE),用于开Android应用程序。它支持前后端分离项目。一般来说,前后端分离项目包含前端和后端两个部分。前端负责用户交互和展示界面,后端负责数据处理和逻辑运算。 在Android Studio中,可以使用Java或Kotlin编写前端代码,通常是通过XML文件定义界面布局,然后在Java或Kotlin文件中处理交互和数据展示。前端代码主要涉及UI设计、界面布局、逻辑处理等。 后端代码一般使用Java编写,可以使用Android Studio中的Java模块或添加Java库来实现。后端主要负责数据处理、数据库连接、API调用、业务逻辑等。 对于前后端分离项目的开流程,可以按照以下步骤进行: 1. 在Android Studio中创建一个新的项目或导入已有的项目。 2. 根据项目需求和设计,使用XML文件定义前端界面布局。 3. 在Java或Kotlin文件中编写前端代码,包括处理用户交互、展示数据等。 4. 在后端部分,可以使用Java编写后端逻辑,包括处理数据、连接数据库、调用API等。 5. 根据项目需求,可以设计和实现前后端的数据交互接口。 6. 运行项目并进行调试,确保前后端的交互和功能正常。 总结来说,Android Studio可以支持前后端分离项目的开,通过编写前端和后端的代码来实现用户交互和数据处理。前端部分负责界面展示和用户交互,后端部分负责数据处理和逻辑运算。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值