• 基于springboot的美食点评APP设计与实现


    目录

    1. 引言 2
      1.1编写目的 2
      1.2项目背景 2
      1.3定义 3
    2. 总体设计 3
      2.1用例图 3
      2.2需求规定 4
      2.3全局变量 4
      2.4运行环境 4
      2.5开发工具 5
    3. UI设计 5
      3.1菜品推荐界面 5
      3.1.1界面简介 5
      3.1.2界面展示 5
      3.2菜品分类搜索 5
      3.2.1界面简介 5
      3.2.2界面展示 5
      3.2菜品详细信息展示界面 6
      3.2.1界面简介 6
      3.2.2界面展示 6
      3.3菜品评价界面 7
      3.3.1界面简介 7
      3.3.2界面展示 7
      3.4登录注册界面 7
      3.4.1界面简介 7
      3.4.2界面展示 7
      3.5用户中心界面 8
      3.5.1界面简介 8
      3.5.2界面展示 8
    4. 接口设计 9
      4.1接口列表 9
      4.2接口说明 13
    5. 项目总结 17
      1.引言
      为适应市场需求,满足顾客方便快捷的搜索到优秀餐饮,快速浏览菜品相关详细信息,本项目计划开发大众美食点评APP,该APP将会满足顾客的食品搜索,食品点评,店家搜索等需求。
      1.1编写目的
      本节描述软件详细设计文档的目的是:
      定义软件总体要求,作为用户和软件开发人员之间互相了解的基础;
      作为软件总体测试和系统结构设计的依据;
      本文档的预期读者包括:软件设计人员、模块开发人员、管理人员、测试人员。
      1.2项目背景
      项目名称:FoodFans;
      项目提出者:XXX;
      开发者:XXX,XXX,XXX;
      1.3定义
      MYSQL:一种免费的功能较强的数据库管理系统
      Android Studio:本文转载自http://www.biyezuopin.vip/onews.asp?id=14920基于IntelliJ IDEA. 类似Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试。
      1.4技术路线:retrofit+room+recyclerview+gridview+listview+livedata
      后端:springboot+mybatis+jwt(token验证)
      3.功能设计
      用户:
      注册、登录、找回密码、更改密码、修改个人信息
      浏览推荐菜谱文章(可含视频)或是通过分类后浏览菜谱文章(可含视频),
      对菜谱进行评论评分、点赞、收藏、分享和打赏
      发表相应菜谱文章(可含视频)
      搜素菜谱文章(可含视频)
      利用自己打赏的积分进行礼品兑换
      管理自己上传的菜谱文章(作品)
      查看自己的最近的浏览历史记录
      可以关注其他人
      关注之后可以发送留言消息
      查看自己的关注列表
      用户可以查看留言列表
      用户可以查看关注自己的粉丝列表

    积分制度:
    用途: 用来兑换系统提供的各种精美礼品
    获得方式: 发表菜谱文章,积分充值,当某篇菜谱点赞数达到一定数量会为作者添加积分,当作者被人关注后也会添加积分。

    package com.star.foodfans.ui.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Color;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.TypedValue;
    import android.view.Gravity;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.WindowManager;
    import android.widget.HorizontalScrollView;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    
    import androidx.viewpager.widget.ViewPager;
    
    import com.star.foodfans.R;
    
    import java.util.List;
    
    
    /**
     * ViewPagerIndicator
     * Created by HaPBoy on 5/10/16.
     */
    public class ViewPagerIndicator extends HorizontalScrollView {
    
        private Context mContext;
    
        private List<String> mTitles; // 接收传递过来的title
        private ViewPager mViewPager; // 接收关联的ViewPager
    
        private LinearLayout llTabRoot; // Tab布局
        private RelativeLayout rlRoot; // 根布局
        private View vLine; // 横线
        private RelativeLayout.LayoutParams lineLayoutParams;
    
        private int mTabVisibleCount; // 可见tab的数量
        private int mSizeText; // tab标签文字大小(sp)
        private int mColorTextNormal; // 正常字体颜色
        private int mColorTextHighlight; // 高亮字体颜色
        private int mColorLine; // 横线颜色
        private int mHeightLine; // 线高(dp)
    
        private static final int COUNT_DEFAULT_TAB = 4; // 默认可见tab为4个
        private static final int SIZE_TEXT = 16; // 默认tab标签文字大小(sp)
        private static final int COLOR_TEXT_NORMAL = Color.parseColor("#000000"); // 默认正常字体颜色
        private static final int COLOR_TEXT_HIGHLIGHT = Color.parseColor("#FFFFFF"); // 默认高亮字体颜色
        private static final int COLOR_LINE = Color.parseColor("#000000"); // 默认横线颜色
        private static final int HEIGHT_LINE = 2; // 默认线高(dp)
    
        public ViewPagerIndicator(Context context) {
            super(context, null);
        }
    
        public ViewPagerIndicator(Context context, AttributeSet attrs) {
            super(context, attrs);
            mContext = context;
    
            // 获取XML中的配置属性
            TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
            mTabVisibleCount = attributes.getInt(R.styleable.ViewPagerIndicator_tab_visible_count, COUNT_DEFAULT_TAB);
            if (mTabVisibleCount < 0) {
                mTabVisibleCount = COUNT_DEFAULT_TAB;
            }
            mSizeText = attributes.getInt(R.styleable.ViewPagerIndicator_tab_text_size, SIZE_TEXT);
            mColorTextNormal = attributes.getInt(R.styleable.ViewPagerIndicator_tab_text_normal_color, COLOR_TEXT_NORMAL);
            mColorTextHighlight = attributes.getInt(R.styleable.ViewPagerIndicator_tab_text_highlight_color, COLOR_TEXT_HIGHLIGHT);
            mColorLine = attributes.getInt(R.styleable.ViewPagerIndicator_tab_line_color, COLOR_LINE);
            mHeightLine = attributes.getInt(R.styleable.ViewPagerIndicator_tab_line_height, HEIGHT_LINE);
            attributes.recycle();
    
            initViews();
        }
    
        private void initViews() {
            setHorizontalScrollBarEnabled(false);
    
            // 根布局
            rlRoot = new RelativeLayout(mContext);
            rlRoot.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            this.addView(rlRoot);
    
            // Tab布局
            llTabRoot = new LinearLayout(mContext);
            llTabRoot.setOrientation(LinearLayout.HORIZONTAL);
            llTabRoot.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            rlRoot.addView(llTabRoot);
    
            // 横线
            vLine = new View(mContext);
            lineLayoutParams = new RelativeLayout.LayoutParams(getScreenWidth() / mTabVisibleCount, DpToPx(mHeightLine));
            lineLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            vLine.setLayoutParams(lineLayoutParams);
            vLine.setBackgroundColor(mColorLine);
            rlRoot.addView(vLine);
        }
    
        /**
         * xml加载完成之后,回调此方法
         * 设置每个tab的LayoutParams
         */
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            int childCount = llTabRoot.getChildCount();
            if (childCount == 0) {
                return;
            }
    
            for (int i = 0; i < childCount; i++) {
                View view = llTabRoot.getChildAt(i);
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
                params.width = getScreenWidth() / mTabVisibleCount;
                view.setLayoutParams(params);
            }
    
            // 横线长度
            lineLayoutParams.width = getScreenWidth() / mTabVisibleCount;
            vLine.setLayoutParams(lineLayoutParams);
        }
    
        /**
         * 动态设置tab的数量
         *
         * @param count
         */
        public void setVisibleTabCount(int count) {
            mTabVisibleCount = count;
            onFinishInflate();
        }
    
        /**
         * 动态设置tab
         *
         * @param titles
         */
        public void setTabItemTitles(List<String> titles) {
            if (titles != null && titles.size() > 0) {
                llTabRoot.removeAllViews();
                mTitles = titles;
                for (String title : mTitles) {
                    llTabRoot.addView(generateTextView(title));
                }
                setItemClickEvent();
            }
        }
    
        /**
         * 根据title创建tab
         *
         * @param title
         * @return view
         */
        private View generateTextView(String title) {
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getScreenWidth() / mTabVisibleCount, LayoutParams.MATCH_PARENT);
    
            TextView textView = new TextView(getContext());
            textView.setText(title);
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mSizeText);
            textView.setTextColor(mColorTextNormal);
            textView.setLayoutParams(params);
            return textView;
        }
    
    
        /**
         * 跟随ViewPager移动
         *
         * @param position
         * @param positionOffset
         */
        public void scroll(int position, float positionOffset) {
            int tabWidth = getWidth() / mTabVisibleCount;
            // 当Tab处于移动至最后一个时
            // position + 1 - (mTabVisibleCount - 1) + positionOffset
            if (position >= (mTabVisibleCount - 2) && positionOffset > 0 && llTabRoot.getChildCount() > mTabVisibleCount) {
                if (mTabVisibleCount != 1) {
                    scrollTo((int) ((position - (mTabVisibleCount - 2) + positionOffset) * tabWidth), 0);
                } else {
                    scrollTo((int) ((position + positionOffset) * tabWidth), 0);
                }
            }
    
            // 移动横线
            lineLayoutParams.leftMargin = (int) ((position + positionOffset) * tabWidth);
            vLine.setLayoutParams(lineLayoutParams);
        }
    
        /**
         * 设置关联的ViewPager
         *
         * @param viewpager
         * @param position
         */
        public void setViewPager(ViewPager viewpager, int position) {
            mViewPager = viewpager;
            mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    
                @Override
                public void onPageSelected(int position) {
                    highLightTextView(position);
                }
    
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    // 滑动Tab和横线
                    scroll(position, positionOffset);
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {
    
                }
            });
            mViewPager.setCurrentItem(position);
            highLightTextView(position);
        }
    
        /**
         * 高亮被点击的tab
         *
         * @param position
         */
        private void highLightTextView(int position) {
            resetTextViewColor();
            View view = llTabRoot.getChildAt(position);
            if (view instanceof TextView) {
                ((TextView) view).setTextColor(mColorTextHighlight);
            }
        }
    
        /**
         * 重置tab文本颜色
         */
        private void resetTextViewColor() {
            for (int i = 0; i < llTabRoot.getChildCount(); i++) {
                View view = llTabRoot.getChildAt(i);
                if (view instanceof TextView) {
                    ((TextView) view).setTextColor(mColorTextNormal);
                }
            }
        }
    
        /**
         * 设置Tab的点击事件
         */
        private void setItemClickEvent() {
            int childCount = llTabRoot.getChildCount();
            for (int i = 0; i < childCount; i++) {
                final int j = i;
                View view = llTabRoot.getChildAt(i);
                view.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mViewPager.setCurrentItem(j);
                    }
                });
            }
        }
    
        /**
         * 获取屏幕的宽度
         *
         * @return screenWidth
         */
        private int getScreenWidth() {
            WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics outMetrics = new DisplayMetrics();
            wm.getDefaultDisplay().getMetrics(outMetrics);
            return outMetrics.widthPixels;
        }
    
        /**
         * 将DP转换为PX
         *
         * @param dp 要转换的像素无关单位
         * @return int
         */
        private int DpToPx(double dp) {
            float scale = getResources().getDisplayMetrics().density;
            return (int) (dp * scale + 0.5f);
        }
    }
    
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Kubernetes 进阶训练营 存储
    【无标题】
    如何在Window系统部署VisualSVN服务并结合cpolar实现无公网ip远程访问
    [{data:{data:[{}]},{data:{data:[{}]}] JS解构赋值拿到内层的data数据
    阿里云云数据库Redis的基本使用(十五)
    Ceph入门到精通-sysctl.conf 配置
    记录软考学习
    .NET静态代码织入——肉夹馍(Rougamo) 发布1.4.0
    数字孪生技术在智慧城市应用的推进建议
    vue 封装一个Dialog组件
  • 原文地址:https://blog.csdn.net/newlw/article/details/127039535