zoukankan      html  css  js  c++  java
  • VS2019创建WebApi+Vue+Element-UI(入门)

    初步思路:创建WebApi编写接口,创建Vue,引用Element-UI,抽取WebApi数据展示

    需要添加的包:

    Autofac.Extensions.DependencyInjection

    Microsoft.EntityFrameworkCore

    Microsoft.EntityFrameworkCore.Design

    AutoMapper.Extensions.Microsoft.DependencyInjection

    Microsoft.EntityFrameworkCore.Tools(DbFirst依据数据库生成实体需要使用)

    Pomelo.EntityFrameworkCore.MySql

    第一步:创建WebApi,VS2019创建项目不再描述。

    Statup.cs

    添加api 控制器、添加DbContext、添加AutoMapper、配置跨域访问(用于Vue调用)、添加AutoFac容器。

    AutoMapper 用于api返回数据与数据库表机构之间转换,AutoFac配置Service和Repository的注入关系

    using System;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Autofac;
    using AdminWebApi.Autofac;
    using Autofac.Extensions.DependencyInjection;
    using DataDAO;
    using Microsoft.EntityFrameworkCore;
    using AutoMapper;
    
    namespace AdminWebApi
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
            public ILifetimeScope AutofacContainer { get; private set; }
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
                //services.AddMvc();
                services.AddDbContext<unified_usersContext>(options => options.UseMySql(Configuration.GetConnectionString("unified_users"), x => x.ServerVersion("5.6.21-mysql")));
                services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
                //必须appsettings.json中配置
                string corsUrls = Configuration["CorsUrls"];
                if (string.IsNullOrEmpty(corsUrls))
                {
                    throw new Exception("请配置跨请求的前端Url");
                }
                //增加允许跨域配置
                 //services.AddCors(m => m.AddPolicy(name:"Any", a => a.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));//开放全部
                //开放指定域名的访问
                services.AddCors(options =>
                {
                    options.AddDefaultPolicy(
                        builder =>
                        {
                            builder.WithOrigins(corsUrls.Split(","))
                            //添加预检请求过期时间
                             .SetPreflightMaxAge(TimeSpan.FromSeconds(2520))
                            .AllowCredentials()
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                        });
                });
            }
            public void ConfigureContainer(ContainerBuilder builder)
            {
                builder.RegisterModule(new AutofacMoule());
            }
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
                //app.UseHttpsRedirection();
                // app.UseCors(bulider => bulider.AllowAnyOrigin());
    
                app.UseRouting();
                //增加允许跨域配置,放在routing 之后 验证之前,顺序很重要
                app.UseCors();//加载默认跨域配置
                //app.UseCors("Any");//加载有命名的策略
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    //endpoints.MapControllers();
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "api/{controller=Users}/{action=index}/{id?}"
                        );
                });
    
            }
        }
    }
    Statup.cs
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    using Autofac.Extensions.DependencyInjection;
    using System.IO;
    
    namespace AdminWebApi
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                //Host.CreateDefaultBuilder(args)
                //    .ConfigureWebHostDefaults(webBuilder =>
                //    {
                //        webBuilder.UseStartup<Startup>();
                //    });
                Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder => {
                    webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                webBuilder.UseStartup<Startup>();
                 //webBuilder.UseUrls("http://localhost:8088");
                    });
        }
    }
    Program.cs

     第二步:编写接口与数据库访问

    添加IRepository和Repository,用于访问数据库,添加IService和Service用于接受处理请求。

    EF Core 参考:https://www.cnblogs.com/zeran/p/11125309.html

    using ModelDto;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using ModelDto.DtoParameters;
    using ModelDto.RUDDto;
    using ModelDto.ViewDto;
    using DataDAO;
    
    namespace AdminWebApi.IRepository
    {
    
        public interface IUsersRepository 
        {
           Task<NtUsers> GetUsers(int UserId);
           Task<IEnumerable<NtUsers>> GetUsersList(UsersDtoParameter usersDtoParameter);
            Task<int> UpdateUser(AddUserDto addUser);
        }
    }
    IRepository.cs
    using AdminWebApi.IRepository;
    using DataDAO;
    using Microsoft.EntityFrameworkCore;
    using ModelDto;
    using ModelDto.DtoParameters;
    using ModelDto.RUDDto;
    using ModelDto.ViewDto;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace AdminWebApi.Repository
    {
        public class UsersRepository : IUsersRepository
        {
            public UsersRepository() { }
            readonly unified_usersContext _Context;
            public UsersRepository(unified_usersContext unifiedUserDbContext)
            {
                _Context = unifiedUserDbContext;
            }
            public async  Task<NtUsers> GetUsers(int UserId)
            {
                return await _Context.NtUsers.Where(n => n.Id== UserId).FirstOrDefaultAsync();
            }
    
            public async Task<IEnumerable<NtUsers>> GetUsersList(UsersDtoParameter usersDtoParameter)
            {
                var query_user = _Context.NtUsers as IQueryable<NtUsers>;//创建筛选条件,
                if (!string.IsNullOrWhiteSpace(usersDtoParameter.name))//筛选姓名
                {
                    usersDtoParameter.name = usersDtoParameter.name.Trim();
                   query_user=query_user.Where(n => n.Name.StartsWith(usersDtoParameter.name));
                }
            return await query_user.Take(usersDtoParameter.pageCount).ToListAsync();//取数据
            }
    
            public async  Task<int> UpdateUser(AddUserDto addUser)
            {
                return 1;
            }
        }
    }
    Repository.cs
    using DataDAO;
    using ModelDto;
    using ModelDto.DtoParameters;
    using ModelDto.RUDDto;
    using ModelDto.ViewDto;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace AdminWebApi.IServices
    {
        public interface IUserService
        {
    
            Task<UsersDto> GetUsers(int UserId);
            Task<IEnumerable<UsersDto>> GetUsersList(UsersDtoParameter usersDtoParameter);
            Task<int> UpdateUser(AddUserDto addUser);
        }
    }
    IServices
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using AdminWebApi.IRepository;
    using AdminWebApi.IServices;
    using AutoMapper;
    using DataDAO;
    using ModelDto;
    using ModelDto.DtoParameters;
    using ModelDto.RUDDto;
    using ModelDto.ViewDto;
    
    namespace AdminWebApi.Service
    {
        public class UserService : IUserService
        {
           readonly IUsersRepository _userpepository;
            private readonly IMapper _mapper;
    
            public UserService(IUsersRepository usersRepository,IMapper mapper)
            {
                _userpepository = usersRepository;
                this._mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
            }
    
            public async  Task<UsersDto> GetUsers(int UserId)
            {
              NtUsers ntusers= await _userpepository.GetUsers(UserId);
                return _mapper.Map<UsersDto>(ntusers);//表结构model转换为Dtomodel,Dto用于暴露在外部
            }
    
            public async Task<IEnumerable<UsersDto>> GetUsersList(UsersDtoParameter usersDtoParameter)
            {
              return  _mapper.Map<IEnumerable<UsersDto>>(await _userpepository.GetUsersList(usersDtoParameter));
            }
    
            public async Task<int> UpdateUser(AddUserDto addUser)
            {
                return await _userpepository.UpdateUser(addUser);
            }
        }
    }
    UserService

    第2.1步:在编写这些代码期间,需要创建DbContext、AutoMapper、AutoFac等

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using AdminWebApi.IServices;
    using AdminWebApi.Service;
    using Autofac;
    
    namespace AdminWebApi.Autofac
    {
        public class AutofacMoule:Module
        {
            protected override void Load(ContainerBuilder builder)
            {
                builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly())//注册整个程序集
                    .Where(n => n.Name.EndsWith("Service")).AsImplementedInterfaces()//注册程序集内以Service结尾的文件
                    .SingleInstance();//单例模式
                //.InstancePerLifetimeScope();
                builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly())
             .Where(n => n.Name.EndsWith("Repository")).AsImplementedInterfaces()//注册程序集内以Repository结尾的文件
             .SingleInstance();
                //builder.RegisterType<twoUserService>().As<IUserService>();
            }
        }
    }
    AutofacMoule.cs

    Statup.cs中引用AutoFac,添加函数

     public void ConfigureContainer(ContainerBuilder builder)
            {
                builder.RegisterModule(new AutofacMoule());
            }

    Program.cs需要按照上面的Program.cs代码段修改

    第2.2步:引用AutoMapper,并编写Dto类,并编写映射关系的UserProfile,AutoMapper 是按照名称进行映射,名称不同不能映射成功,可以在映射是对某个字段进行处理

    using System;
    using System.Collections.Generic;
    using System.Text;
    using ModelDto.ViewDto;
    using ModelDto.RUDDto;
    using AutoMapper;
    
    namespace DataDAO.profiles
    {
        class UserProfile : Profile
        {
            public UserProfile()
            {
                CreateMap<NtUsers, UsersDto>()
                    .ForMember(
                    u => u.name,
                    opt => opt.MapFrom(
                        dto => dto.Name+dto.NickName
                        )
                    );
            }
        }
    }
    UserProfile.cs

    添加后需要在Sturtup中的ConfigureService 添加

     services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

    第三步:编写api接口,RESTful Web API是按照http动词(get/post/put/delete/options等)请求接口的,比如接口上增加[HttpPost]无论接口命名是什么只要是post请求都调用这个接口,

    指定接口名称使用[HttpPost("getuserlist")]或者[HttpPost(nameof(接口名))]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using ModelDto;
    using Autofac;
    using AdminWebApi.IServices;
    using ModelDto.ViewDto;
    using ModelDto.DtoParameters;
    using System.Net.Mime;
    using Microsoft.AspNetCore.Cors;
    
    namespace AdminWebApi.Controllers
    {
        [EnableCors]//加载默认跨域配置
        //[EnableCors("Any")]//加载有命名的跨域策略
        [ApiController]
        [Route("api/[controller]")]
        //[Produces(MediaTypeNames.Application.Json)]    
        public class AdminUserController : ControllerBase
        {
            readonly IUserService _userservice;
            public AdminUserController(IUserService userService)
            {
                _userservice = userService;
            }
            [HttpGet("getuserByid")]
            public async Task<UsersDto> GetDtoAsync(int uid)
            {
                return  await _userservice.GetUsers(uid);
            }
            [HttpPost("getuserlist")]
            [HttpOptions]
            public async Task<IEnumerable<UsersDto>> GetUserDtoAsync(UsersDtoParameter dtoParameter)
            {
                return await _userservice.GetUsersList(dtoParameter);
            }
        }
    }
    AdminUserController.cs

     这时使用postman 请求接口能够正常返回数据。postman不涉及跨域问题。

    第四步:创建Vue项目并饮用Element-ui,VS2019可以创建Vue项目,没有的话先安装VS2019的Node.JS支持

    Vue的启动文件是Main.js引用第三方js 可以在indexhtml的body之前

    需要先在项目路径下安装 Element-ui,axios(用于请求后端数据)

    npm i element-ui -S
    npm install axios -S
    import Vue from 'vue';
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    import App from './App.vue';
    import axios from 'axios';//引用axios 用于请求数据
    import qs from 'qs';
    
    Vue.config.productionTip = true;
    Vue.use(ElementUI);//注册组件
    Vue.component(ElementUI);
    //Vue.use(axios);//
    Vue.prototype.$axios = axios;//相当于定义变量,没太搞清
    Vue.prototype.$qs = qs;
    
    //跨域问题处理开始,实际没效果,后端开放跨域就可以
    Vue.prototype.HOST = '/api';
    var http = axios.create({
        baseURL: 'http://127.0.0.1:5000/',
        timeout: 10000
    });
    axios.defaults.headers.post['Content-Type'] = 'application/json';
    //axios.defaults.baseUrl = "/api";
    Vue.http = http;
    //跨域问题处理 结束
    
    
    new Vue({
        el: '#app', 
        render: h => h(App)
       
    }).$mount('#app');
    Main.js
    <template>
        <div id="app">
            
            <el-container>
                <el-header><Header /></el-header>
                <el-container>
                    <el-aside width="200px"><Left_menu /></el-aside>
                    <el-main><Home /></el-main>
                </el-container>
            </el-container>
    
        </div>
    </template>
    
    <script>
        import Home from './components/Home.vue';
        import Header from './components/Header.vue';
        import Left_menu from './components/Left_menu.vue';
        export default {
            name: 'app',
            components: {
                
                Header,
                Left_menu,
                Home
            }
        };
    </script>
    
    <style>
        @import url("//unpkg.com/element-ui@2.14.0/lib/theme-chalk/index.css");
    
        .el-header, .el-footer {
            background-color: #B3C0D1;
            color: #333;
            text-align: center;
            line-height: 60px;
        }
    
        .el-aside {
            background-color: #D3DCE6;
            color: #333;
            text-align: center;
            line-height: 200px;
        }
    
        .el-main {
            background-color: #E9EEF3;
            color: #333;
            text-align: center;
            line-height: 160px;
        }
    
        body > .el-container {
            margin-bottom: 40px;
        }
    
        .el-container:nth-child(5) .el-aside,
        .el-container:nth-child(6) .el-aside {
            line-height: 260px;
        }
    
        .el-container:nth-child(7) .el-aside {
            line-height: 320px;
        }
    </style>
    App.vue

    Left_menu、Header内容只是Element-ui的样式,不贴代码了

    <template>
        <div class="home">
            <template>
                <el-table :data="tableData2"
                          style=" 100%" :key="Math.random()">
                    <el-table-column prop="login_name"
                                     label="登录名"
                                     width="180">
                    </el-table-column>
                    <el-table-column prop="name"
                                     label="姓名"
                                     width="180">
                    </el-table-column>
                    <el-table-column prop="cellphone"
                                     label="地址">
                    </el-table-column>
                    
                </el-table>
            </template>
    
        </div>
    </template>
    
    <script>
       // var tabelData;
        
        export default {
            //data() 为函数,mounted methods 均为vue生命周期内的不同内容,写法与顺序 暂时没搞清
            data() {
                return {
                    tableData2: []//定义以及初始化数据
                }
            },
            mounted() {// 或者 mounted: function() {
                this.getData();
            },
            methods: {
                 getData() {
                    let params = new URLSearchParams()
                    params.append("name", "学员");
                    //$axios 是引用 的axios 的组件,定义的变量
                    //后台接受参数是application/json 格式,需要指定content-type,不指定Content-type 或者不对应会报415 媒体类型不正确错误
                    //参数需要 JSON.stringify 对象转成字符串,不然会报400错误,
                    this.$axios.post("http://127.0.0.1:5000/api/adminuser/getuserlist",//vue和后端webapi 会出现跨域情况,需要webapi内的startup 增加允许跨域配置,详见后端
                        JSON.stringify(params), {
                        headers: {
                            'Content-Type': 'application/json;charset=UTF-8'
                        }
                    }).then(msg=> {
                        this.tableData2 = msg.data;//为定义的数据赋值
    
                        //this.tabelData2 需要加this ,这里的this 是生命周期内的(要使用then(msg=>{})方式)
                        //如果使用then(function(msg){}) 方式 this表示window内,会报错 tableData2未定义,解决方案:
                        // 在vue生命周期内定义常量 const that=this; function 内 改为that.tableData2=msg.data;
                    });
                }
            }
        }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    </style>
    Home.vue

    Home.vue的逻辑只是动态给table赋值,请求了api接口,遇到的问题比较多。特地记录一下

    1、vue生命周期问题,暂时没搞懂,exprot default{data(){return ……},mounted(){},methods:{}} 其中data和mounted是函数,menthods是属性,这些执行是有先后顺序的。首先需要在data中定义并初始化数据,在mounted内计算。

    其中getData()函数内的$axios.post()错了很多次才调整好语法(还是语法不了解呀T_T)

    this表示window,代表整个页面,使用msg=>{this.XXX} 这里边的this代表局部 function(msg){this.XXX}这里的this表示window
    400错误和415错误
    2、类型不正确会报415错误:API接口接受的 'Content-Type'类型是 'application/json;charset=UTF-8',所以需要加headers{ 'Content-Type': 'application/json;charset=UTF-8'},默认是
    application/x-www-form-urlencoded
    3、参数不被识别会报400错误:参数需要JSON.stringify转为字符串,我个人理解是传递的是对象,但是后端需要的是json字符串,需要转换,不然会报400错误。
    重要的一点:跨域
    一般Vue都是和后端分离的,所以涉及到跨域问题,所以需要后端设置
    首先需要在appsettings.json中添加允许访问的域
    "CorsUrls": "http://localhost:1337,http://127.0.0.1:1337,http://127.0.0.1:8081,http://127.0.0.1:8080,http://172.21.210.1:1337"
    Startup.cs中的ConfigureServices增加跨域设置,可以设置全部,也可以设置指定的域
     //必须appsettings.json中配置
                string corsUrls = Configuration["CorsUrls"];
                if (string.IsNullOrEmpty(corsUrls))
                {
                    throw new Exception("请配置跨请求的前端Url");
                }
                //增加允许跨域配置
                 //services.AddCors(m => m.AddPolicy(name:"Any", a => a.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));//开放全部
                //开放指定域名的访问
                services.AddCors(options =>
                {
                    options.AddDefaultPolicy(
                        builder =>
                        {
                            builder.WithOrigins(corsUrls.Split(","))
                            //添加预检请求过期时间
                             .SetPreflightMaxAge(TimeSpan.FromSeconds(2520))
                            .AllowCredentials()
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                        });
                });
    Cors配置
    在Configure中需要在app.UseRoting()和app.UseAuthorization()之间添加:app.UseCors();
    在Api的Controller上添加[EnableCors]
    简单记录一下 配置带名称的Cors规则和default的默认规则,有些资源可以公开访问,有些资源只允许某些用户或域名访问,比如新闻是允许公开访问的,用户信息是限定的,就可以定义不同名称的Cors规则,Controller上使用[EnableCors("名称")]
    代码位置:https://gitee.com/zeran/NetCore3.X-WebApi-Vue-AutoFac
    仅供参考,内容中会引用部分博友的文章。(侵删)
  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    Spring|SpringMVC中的注解
    Spring Boot
    Java模板引擎Freemarker
    Spring Boot整合Spring Data JPA
    Java性能优化,操作系统内核性能调优,JYM优化,Tomcat调优
    将字符串进行md5加密
    equals()方法和hashCode()方法
  • 原文地址:https://www.cnblogs.com/zeran/p/13964946.html
Copyright © 2011-2022 走看看