基Android实现网上商城的系统开发(附带源码)

主要代码

  1. HomeActivity.java
    代码如下:

package com.itau.jingdong.ui;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.TabActivity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.TabHost;
import android.widget.RadioGroup.OnCheckedChangeListener;

import com.itau.jingdong.AppManager;
import com.itau.jingdong.R;
import com.nostra13.universalimageloader.core.ImageLoader;
//主页面
public class HomeActivity extends TabActivity {
//打印日志标记
public static final String TAG = HomeActivity.class.getSimpleName();
//定义一个单选按钮组 用于切换底部选项栏
private RadioGroup mTabButtonGroup;
private TabHost mTabHost;//选项卡组件
//定义选项卡对应的类名
public static final String TAB_MAIN = “MAIN_ACTIVITY”;//主页
public static final String TAB_SEARCH = “SEARCH_ACTIVITY”;//查询
public static final String TAB_CATEGORY = “CATEGORY_ACTIVITY”;//分类
public static final String TAB_CART = “CART_ACTIVITY”;//购物车
public static final String TAB_PERSONAL = “PERSONAL_ACTIVITY”;//个人

@Override
protected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);AppManager.getInstance().addActivity(this);setContentView(R.layout.activity_home);findViewById();//绑定控件initView();
}private void findViewById() {//绑定单选按钮组控件mTabButtonGroup = (RadioGroup) findViewById(R.id.home_radio_button_group);
}private void initView() {//获取选项mTabHost = getTabHost();//定义响应的intent对象Intent i_main = new Intent(this, IndexActivity.class);Intent i_search = new Intent(this, SearchActivity.class);Intent i_category = new Intent(this, CategoryActivity.class);Intent i_cart = new Intent(this, CartActivity.class);Intent i_personal = new Intent(this, PersonalActivity.class);//将选项与对应页面加入tab项mTabHost.addTab(mTabHost.newTabSpec(TAB_MAIN).setIndicator(TAB_MAIN).setContent(i_main));mTabHost.addTab(mTabHost.newTabSpec(TAB_SEARCH).setIndicator(TAB_SEARCH).setContent(i_search));mTabHost.addTab(mTabHost.newTabSpec(TAB_CATEGORY).setIndicator(TAB_CATEGORY).setContent(i_category));mTabHost.addTab(mTabHost.newTabSpec(TAB_CART).setIndicator(TAB_CART).setContent(i_cart));mTabHost.addTab(mTabHost.newTabSpec(TAB_PERSONAL).setIndicator(TAB_PERSONAL).setContent(i_personal));//设置当前显示页mTabHost.setCurrentTabByTag(TAB_MAIN);//设置单选监听事件 根据单选项跳转至指定页面mTabButtonGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {public void onCheckedChanged(RadioGroup group, int checkedId) {switch (checkedId) {//主页面case R.id.home_tab_main:mTabHost.setCurrentTabByTag(TAB_MAIN);break;//查询页面case R.id.home_tab_search:mTabHost.setCurrentTabByTag(TAB_SEARCH);break;//分类页面case R.id.home_tab_category:mTabHost.setCurrentTabByTag(TAB_CATEGORY);break;//购物车页面case R.id.home_tab_cart:mTabHost.setCurrentTabByTag(TAB_CART);break;//用户信息页面case R.id.home_tab_personal:mTabHost.setCurrentTabByTag(TAB_PERSONAL);break;default:break;}}});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {//加载菜单项getMenuInflater().inflate(R.menu.activity_menu, menu);return true;
}
//根据菜单项跳转至不同页面
@Override
public boolean onOptionsItemSelected(MenuItem item) {// TODO Auto-generated method stubswitch (item.getItemId()) {case R.id.menu_about:break;case R.id.menu_setting:break;case R.id.menu_history:break;case R.id.menu_feedback:break;case R.id.menu_exit://启动退出页面对话框showAlertDialog("退出程序", "确定退出京东商城?", "确定", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubAppManager.getInstance().AppExit(getApplicationContext());ImageLoader.getInstance().clearMemoryCache();}}, "取消", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubdialog.dismiss();}});break;case R.id.menu_help:break;default:break;}return true;
}
//显示一个对话框 有两个按钮
protected void showAlertDialog(String title, String message,String positiveText,DialogInterface.OnClickListener onPositiveClickListener,String negativeText,DialogInterface.OnClickListener onNegativeClickListener) {//创建一个含有确定 取消的 对话框new AlertDialog.Builder(this).setTitle(title).setMessage(message).setPositiveButton(positiveText, onPositiveClickListener).setNegativeButton(negativeText, onNegativeClickListener).show();//记得设置显示
}

}

在这里插入图片描述

文件:url80.ctfile.com/f/25127180-735569552-34e4ac?p=551685 (访问密码: 551685)


前端上传文件时,无论是使用比较传统的表单,还是使用FormData对象,其本质都是发送一个multipart/form-data请求。

例如,前端模拟上传代码如下:

var formdata = new FormData();
formdata.append(“key1”, “value1”);
formdata.append(“key2”, “value2”);
formdata.append(“file1”, fileInput.files[0], “/d:/Downloads/rfc1867.pdf”);
formdata.append(“file2”, fileInput.files[0], “/d:/Downloads/rfc1314.pdf”);

var requestOptions = {
method: ‘POST’,
body: formdata,
redirect: ‘follow’
};

fetch(“http://localhost:10001/file/upload”, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log(‘error’, error));
实际会发送如下HTTP请求:

POST /file/upload HTTP/1.1
Host: localhost:10001
Content-Length: 536
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=“key1”

value1
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=“key2”

value2
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=“file1”; filename=“/d:/Downloads/rfc1867.pdf”
Content-Type: application/pdf

(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=“file2”; filename=“/d:/Downloads/rfc1314.pdf”
Content-Type: application/pdf

(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW

在后端可以通过MultipartHttpServletRequest接收文件:

@RestController
@RequestMapping(“file”)
public class FileUploadController {
@RequestMapping(“/upload”)
public String upload(MultipartHttpServletRequest request) {
// 获取非文件参数
String value1 = request.getParameter(“key1”);
System.out.println(value1); // value1
String value2 = request.getParameter(“key2”);
System.out.println(value2); // value2
// 获取文件
MultipartFile file1 = request.getFile(“file1”);
System.out.println(file1 != null ? file1.getOriginalFilename() : “null”); // rfc1867.pdf
MultipartFile file2 = request.getFile(“file2”);
System.out.println(file2 != null ? file2.getOriginalFilename() : “null”); // rfc1314.pdf
return “Hello MultipartResolver!”;
}
}
2 MultipartResolver接口#
2.1 MultipartResolver的功能#
org.springframework.web.multipart.MultipartResolver是Spring-Web根据RFC1867规范实现的多文件上传的策略接口。
同时,MultipartResolver是Spring对文件上传处理流程在接口层次的抽象。
也就是说,当涉及到文件上传时,Spring都会使用MultipartResolver接口进行处理,而不涉及具体实现类。
MultipartResolver接口源码如下:

public interface MultipartResolver {
/**
* 判断当前HttpServletRequest请求是否是文件请求
/
boolean isMultipart(HttpServletRequest request);
/
*
* 将当前HttpServletRequest请求的数据(文件和普通参数)封装成MultipartHttpServletRequest对象
/
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;
/
*
* 清除文件上传产生的临时资源(如服务器本地临时文件)
*/
void cleanupMultipart(MultipartHttpServletRequest request);
}
2.2 在DispatcherServlet中的使用#
DispatcherServlet中持有MultipartResolver成员变量:

public class DispatcherServlet extends FrameworkServlet {
/** Well-known name for the MultipartResolver object in the bean factory for this namespace. /
public static final String MULTIPART_RESOLVER_BEAN_NAME = “multipartResolver”;
/
* MultipartResolver used by this servlet. */
@Nullable
private MultipartResolver multipartResolver;
}
DispatcherServlet在初始化时,会从Spring容器中获取名为multipartResolver的对象(该对象是MultipartResolver实现类),作为文件上传解析器:

/**

  • Initialize the MultipartResolver used by this class. *

    If no bean is defined with the given name in the BeanFactory for this namespace,

  • no multipart handling is provided. */
    private void initMultipartResolver(ApplicationContext context) {
    try {
    this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
    if (logger.isTraceEnabled()) {
    logger.trace("Detected " + this.multipartResolver);
    }
    else if (logger.isDebugEnabled()) {
    logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
    }
    }
    catch (NoSuchBeanDefinitionException ex) {
    // Default is no multipart resolver.
    this.multipartResolver = null;
    if (logger.isTraceEnabled()) {
    logger.trace(“No MultipartResolver '” + MULTIPART_RESOLVER_BEAN_NAME + “’ declared”);
    }
    }
    }
    需要注意的是,如果Spring容器中不存在名为multipartResolver的对象,DispatcherServlet并不会额外指定默认的文件解析器。此时,DispatcherServlet不会对文件上传请求进行处理。也就是说,尽管当前请求是文件请求,也不会被处理成MultipartHttpServletRequest,如果我们在控制层进行强制类型转换,会抛异常。

DispatcherServlet在处理业务时,会按照顺序分别调用这些方法进行文件上传处理,相关核心源码如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
boolean multipartRequestParsed = false;
try {
// 判断&封装文件请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 请求处理……
}
finally {
// 清除文件上传产生的临时资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
在checkMultipart()方法中,会进行判断、封装文件请求:

/**

  • Convert the request into a multipart request, and make multipart resolver available. *

    If no multipart resolver is set, simply use the existing request.

  • @param request current HTTP request
  • @return the processed request (multipart wrapper if necessary) * @see MultipartResolver#resolveMultipart
    */
    protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
    if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
    if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
    if (DispatcherType.REQUEST.equals(request.getDispatcherType())) {
    logger.trace(“Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter”);
    }
    }
    else if (hasMultipartException(request)) {
    logger.debug("Multipart resolution previously failed for current request - " +
    “skipping re-resolution for undisturbed error rendering”);
    }
    else {
    try {
    return this.multipartResolver.resolveMultipart(request);
    }
    catch (MultipartException ex) {
    if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
    logger.debug(“Multipart resolution failed for error dispatch”, ex);
    // Keep processing error dispatch with regular request handle below
    }
    else {
    throw ex;
    }
    }
    }
    }
    // If not returned before: return original request.
    return request;
    }
    总的来说,DispatcherServlet处理文件请求会经过以下步骤:

判断当前HttpServletRequest请求是否是文件请求
是:将当前HttpServletRequest请求的数据(文件和普通参数)封装成MultipartHttpServletRequest对象
不是:不处理
DispatcherServlet对原始HttpServletRequest或MultipartHttpServletRequest对象进行业务处理
业务处理完成,清除文件上传产生的临时资源
2.3 MultipartResolver实现类&配置方式#
Spring提供了两个MultipartResolver实现类:

org.springframework.web.multipart.support.StandardServletMultipartResolver:根据Servlet 3.0+ Part Api实现
org.springframework.web.multipart.commons.CommonsMultipartResolver:根据Apache Commons FileUpload实现
在Spring Boot 2.0+中,默认会在org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration中创建StandardServletMultipartResolver作为默认文件解析器:

@AutoConfiguration
@ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
@ConditionalOnProperty(prefix = “spring.servlet.multipart”, name = “enabled”, matchIfMissing = true)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {

private final MultipartProperties multipartProperties;

public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
this.multipartProperties = multipartProperties;
}

@Bean
@ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class })
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}

@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
}
当需要指定其他文件解析器时,只需要引入相关依赖,然后配置一个名为multipartResolver的bean对象:

@Bean
public MultipartResolver multipartResolver() {
MultipartResolver multipartResolver = …;
return multipartResolver;
}
接下来,我们分别详细介绍两种实现类的使用和原理。

3 StandardServletMultipartResolver解析器#
3.1 StandardServletMultipartResolver#isMultipart#
StandardServletMultipartResolver解析器的通过判断请求的Content-Type来判断是否是文件请求:

public boolean isMultipart(HttpServletRequest request) {
return StringUtils.startsWithIgnoreCase(request.getContentType(),
(this.strictServletCompliance ? “multipart/form-data” : “multipart/”));
}
其中,strictServletCompliance是StandardServletMultipartResolver的成员变量,默认false,表示是否严格遵守Servlet 3.0规范。简单来说就是对Content-Type校验的严格程度。如果strictServletCompliance为false,请求头以multipart/开头就满足文件请求条件;如果strictServletCompliance为true,则需要请求头以multipart/form-data开头。

3.2 StandardServletMultipartResolver#resolveMultipart#
StandardServletMultipartResolver在解析文件请求时,会将原始请求封装成StandardMultipartHttpServletRequest对象:

public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}
需要注意的是,这里传入this.resolveLazily成员变量,表示是否延迟解析。我们可以来看对应构造函数源码:

public StandardMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing)
throws MultipartException {

super(request);
if (!lazyParsing) {
parseRequest(request);
}
}
如果需要修改resolveLazily成员变量的值,需要在初始化StandardServletMultipartResolver时指定值。
在Spring Boot 2.0+中,默认会在org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration中创建StandardServletMultipartResolver作为默认文件解析器,此时会从MultipartProperties中读取resolveLazily值。因此,如果是使用Spring Boot 2.0+默认配置的文件解析器,可以在properties或.yml文件中指定resolveLazily值:

spring.servlet.multipart.resolve-lazily=true
如果是使用自定义配置的方式配置StandardServletMultipartResolver,则可以在初始化的手动赋值:

@Bean
public MultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(true);
return multipartResolver;
}
3.3 StandardMultipartHttpServletRequest#parseRequest#
当resolveLazily为true时,会马上调用parseRequest()方法会对请求进行实际解析,该方法会完成两件事情:

使用Servlet 3.0的Part API,获取Part集合
解析Part对象,封装表单参数和表单文件
private void parseRequest(HttpServletRequest request) {
try {
Collection parts = request.getParts();
this.multipartParameterNames = new LinkedHashSet<>(parts.size());
MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap<>(parts.size());
for (Part part : parts) {
String headerValue = part.getHeader(HttpHeaders.CONTENT_DISPOSITION);
ContentDisposition disposition = ContentDisposition.parse(headerValue);
String filename = disposition.getFilename();
if (filename != null) {
if (filename.startsWith(“=?”) && filename.endsWith(“?=”)) {
filename = MimeDelegate.decode(filename);
}
files.add(part.getName(), new StandardMultipartFile(part, filename));
}
else {
this.multipartParameterNames.add(part.getName());
}
}
setMultipartFiles(files);
}
catch (Throwable ex) {
handleParseFailure(ex);
}
}
经过parseRequest()方法处理,我们在业务处理时,直接调用StandardMultipartHttpServletRequest接口的getXxx()方法就可以获取表单参数或表单文件信息。

当resolveLazily为false时,在MultipartResolver#resolveMultipart()阶段并不会进行文件请求解析。也就是说,此时StandardMultipartHttpServletRequest对象的成员变量都是空值。那么,resolveLazily为false时文件请求解析是在什么时候完成的呢?
实际上,在调用StandardMultipartHttpServletRequest接口的getXxx()方法时,内部会判断是否已经完成文件请求解析。如果未解析,就会调用partRequest()方法进行解析,例如:

@Override
public Enumeration getParameterNames() {
if (this.multipartParameterNames == null) {
initializeMultipart(); // parseRequest(getRequest());
}
// 业务处理……
}
3.4 HttpServletRequest#getParts#
根据StandardMultipartHttpServletRequest#parseRequest源码可以发现,StandardServletMultipartResolver解析文件请求依靠的是HttpServletRequest#getParts方法。
这是StandardServletMultipartResolver是根据标准Servlet 3.0实现的核心体现。
在Servlet 3.0中定义了javax.servlet.http.Part,用来表示multipart/form-data请求体中的表单数据或文件:

public interface Part {
public InputStream getInputStream() throws IOException;
public String getContentType();
public String getName();
public String getSubmittedFileName();
public long getSize();
public void write(String fileName) throws IOException;
public void delete() throws IOException;
public String getHeader(String name);
public Collection getHeaders(String name);
public Collection getHeaderNames();
}
在javax.servlet.http.HttpServletRequest,提供了获取multipart/form-data请求体各个part的方法:

public interface HttpServletRequest extends ServletRequest {
/**
* Return a collection of all uploaded Parts.
*
* @return A collection of all uploaded Parts.
* @throws IOException
* if an I/O error occurs
* @throws IllegalStateException
* if size limits are exceeded or no multipart configuration is
* provided
* @throws ServletException
* if the request is not multipart/form-data
* @since Servlet 3.0
*/
public Collection getParts() throws IOException, ServletException;

/**  * Gets the named Part or null if the Part does not exist. Triggers upload     * of all Parts.    *     * @param name The name of the Part to obtain  *     * @return The named Part or null if the Part does not exist    * @throws IOException  *             if an I/O error occurs  * @throws IllegalStateException  *             if size limits are exceeded  * @throws ServletException  *             if the request is not multipart/form-data  * @since Servlet 3.0     */    
public Part getPart(String name) throws IOException, ServletException;  

}
所有实现标准Servlet 3.0规范的Web服务器,都必须实现getPart()/getParts()方法。也就是说,这些Web服务器在解析请求时,会将multipart/form-data请求体中的表单数据或文件解析成Part对象集合。通过HttpServletRequest的getPart()/getParts()方法,可以获取这些Part对象,进而获取multipart/form-data请求体中的表单数据或文件。
每个Web服务器对Servlet 3.0规范都有自己的实现方式。对于Spring Boot来说,通常使用的是Tomcat/Undertow/Jetty内嵌Web服务器。通常只需要了解这三种服务器的实现方式即可。

3.4.1 Tomcat实现#
Tomcat是Spring Boot默认使用的内嵌Web服务器,只需要引入如下依赖:

org.springframework.boot spring-boot-starter-web 会默认引入Tomcat依赖: org.springframework.boot spring-boot-starter-tomcat Tomcat解析文件请求的核心在于org.apache.catalina.connector.Request#parseParts方法,核心代码如下:

// 1、创建ServletFileUpload文件上传对象
DiskFileItemFactory factory = new DiskFileItemFactory();
try {
factory.setRepository(location.getCanonicalFile());
} catch (IOException ioe) {
parameters.setParseFailedReason(FailReason.IO_ERROR);
partsParseException = ioe;
return;
}
factory.setSizeThreshold(mce.getFileSizeThreshold());

ServletFileUpload upload = new ServletFileUpload();
upload.setFileItemFactory(factory);
upload.setFileSizeMax(mce.getMaxFileSize());
upload.setSizeMax(mce.getMaxRequestSize());
this.parts = new ArrayList<>();
try {
// 2、解析文件请求
List items =
upload.parseRequest(new ServletRequestContext(this));
// 3、封装Part对象
for (FileItem item : items) {
ApplicationPart part = new ApplicationPart(item, location);
this.parts.add(part);
}
}
success = true;
}
核心步骤如下:

创建ServletFileUpload文件上传对象
解析文件请求
封装Part对象
org.apache.tomcat.util.http.fileupload.FileUploadBase#parseRequest会进行实际解析文件请求:

public List parseRequest(final RequestContext ctx) throws FileUploadException {
final List items = new ArrayList<>();
boolean successful = false;
try {
final FileItemIterator iter = getItemIterator(ctx);
final FileItemFactory fileItemFactory = Objects.requireNonNull(getFileItemFactory(),
“No FileItemFactory has been set.”);
final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE];
while (iter.hasNext()) {
final FileItemStream item = iter.next();
// Don’t use getName() here to prevent an InvalidFileNameException.
final String fileName = item.getName();
final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(),
item.isFormField(), fileName);
items.add(fileItem);
try {
Streams.copy(item.openStream(), fileItem.getOutputStream(), true, buffer);
} catch (final FileUploadIOException e) {
throw (FileUploadException) e.getCause();
} catch (final IOException e) {

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1380199.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]计算机毕业设计基于Springboot的手机电商网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Destoon7.0绿色行业B2B大气平台门户全站源码/带手机版+商务中心网站商城系统源码

非常大气的一套destoon系统&#xff0c;适用于各种B2B行业网站&#xff0c;功能强大完善&#xff0c;带商务会员中心&#xff01;Destoon7.0内核&#xff0c;带安装说明&#xff0c;并附赠火车头采集接口以及185套公司模板。站长亲测非常完美&#xff0c;有需要的下载吧。 下载…

(纯原创) 基于JAVAWEB的网上购物平台(完整源代码以及开发文档)

摘要 随着计算机网络技术的飞速发展和人们生活节奏的不断加快&#xff0c;电子商务技术已经逐渐融入了人们的日常生活当中&#xff0c;网上商城作为电子商务最普遍的一种形式&#xff0c;已被大众逐渐接受。因此开发一个网上商城系统&#xff0c;适合当今形势&#xff0c;更…

【android精品源码系列】安卓线上购物商城

安卓线上购物商城【源码推荐】 简介效果演示首页分类购物车我的 获取方式关于我 简介 分享一个非常优秀的Android商城&#xff0c;功能非常完备&#xff0c;主要功能有&#xff1a; 1.首页不同item展示商品&#xff0c;轮播图等2.商品详情立即购买和加入购物车3.商品的分类&a…

Android在线源码网站推荐

Android开发过程中调用的Android SDK中framework jar提供的源码&#xff0c;这部分不包括hide的内容和非framework的代码&#xff0c;但解决一般的问题可以尝试使用此方式。 1、http://aospxref.com/ 优点&#xff1a;更新速度快 缺点&#xff1a;历史版本较少 2、http://an…

电子商务网站源码HTML5+CSS3+JavaScript

电子商务网站 利用CSS3HTML5Jquery开发的一个电商网站页面&#xff0c;代码都有详细注释&#xff0c;希望能帮到你们&#xff0c;下面是页面的展示。源代码在GitHub上&#xff0c;地址&#xff1a;https://github.com/PowerDos/Mall 首页动态图片 图片比较大&#xff0c;可能…

【源码分享】java多用户B2B2C商城源码带WAP手机端源码

分享一款非常不错的java多用户B2B2C商城源码&#xff0c;带WAP手机端源码&#xff0c;源码地址在文末。 需要源码学习&#xff0c;可私信我获取。 一、技术构架&#xff1a; 开发语言&#xff1a; Java1.7 数 据 库 &#xff1a; MySQL5.5 数据库持久层&#xff1a;阿里巴巴…

2023最新手机流量卡充值管理系统网站源码+内附搭建教程

正文: 市面上很火的流量卡项目&#xff0c;可以用这套平台系统来管理&#xff0c;实现自定义套餐名以及流量卡运营&#xff0c;充值收款&#xff0c;即时返佣以及流量卡运营&#xff0c;内附搭建教程。 程序: wwxrhs.lanzoul.com/i3RRK0kx6q1c 图片:

java连接sqlserver细节处理

这个文章记录一下java连接sqlserver细节处理 &#xff0c;有其他的细节可以评论。 首先是 驱动 driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriverpom文件 将mysql的改成这个 <!-- 数据库驱动 --><dependency><groupId>com.microsoft.sqlserve…

Android 10还没适配完,Android 11又要出了?

在谷歌的内部峰会视频中出现了一页幻灯片&#xff0c;其中明确给出了Android 11正式版将于9月8日&#xff08;周二&#xff09;正式发布的消息。 去年Android 10是9月3日正式上线的&#xff0c;这次Android11在9月8日推出也并不令人奇怪。预计届时&#xff0c;系统源码会上传到…

一文看懂:小程序分享到朋友圈【建议收藏】

点击上方 关注我们 作者简介 张所勇 转转平台运营中心前端负责人&#xff0c;在前端领域有深入研究&#xff0c;包括&#xff1a;sketch一键切图、前端数据模型化&#xff0c;小程序基础能力建设等多个方面&#xff0c;10年工作经验中&#xff0c;做了2年工程师&#xff0c;5年…

【小程序】766- 一文看懂小程序分享到朋友圈

点击上方 关注我们 作者简介 张所勇 转转平台运营中心前端负责人&#xff0c;在前端领域有深入研究&#xff0c;包括&#xff1a;sketch一键切图、前端数据模型化&#xff0c;小程序基础能力建设等多个方面&#xff0c;10年工作经验中&#xff0c;做了2年工程师&#xff0c;5年…

AMD高保真超分算法1.0解密

FSR 1.0是空间滤波算法&#xff0c;分成EASU和RCAS两部分。EASU是边缘适配的空间上采样(Edge Adaptive Spatial Upsampling)&#xff0c;RCAS是健壮对比度适配锐化(Robust Contrast Adaptive Sharpening)&#xff0c;从CAS发展而来。 Lanczos 采样及多项式拟合 FSR 1.0 使用了 …

windows10怎么显示文件后缀(扩展名)?

随意点击一个文件夹&#xff0c;点击查看&#xff1a; 勾选文件扩展名&#xff1a; 即可看到文件扩展名&#xff1a; 参考文章&#xff1a;windows电脑怎么显示文件后缀

windows如何显示文件扩展名称?

本文教程主要介绍一下&#xff0c;windows系统如何显示文件扩展名称&#xff08;默认情况下文件扩展名称是隐藏的&#xff09;。 下面提供目前主流的操作系统版本&#xff08;win7,win10,win11&#xff09;的显示文件扩展名称的方法。 目录 一、windows7设置方法 二、windows…

win10显示文件扩展名、隐藏文件

win10显示文件扩展名、隐藏文件 打开任意一个文件夹&#xff0c;点击右上角的【展开功能区】按钮&#xff0c;如下图&#xff1a; 点击【查看】按钮&#xff0c;勾选【文件扩展名】和【隐藏的项目】

Win7如何显示文件扩展名

有时&#xff0c;我们想知道或者需要修改电脑中某个文件的扩展名&#xff0c;即通常所说的文件格式&#xff0c;但是重命名后发现还是和没改一样。在Windows系统中&#xff0c;这是因为文件的扩展名通常默认是隐藏的&#xff0c;而在此情况下重命名操作修改的只是文件的文件名&…

RCNA——单臂路由

一&#xff0c;实验背景 之前的VLAN实现的很多都是相同部门互相访问&#xff0c;不同部门无法访问。不过这次整来了一个路由器&#xff0c;领导说大部分的部门虽说有保密信息需要互相隔离&#xff0c;但是这些部门和其它部门也应该互相连通以方便工作交流。因此要配置新的环境&…

[Mongodb 5.0]单机启动

安装完mongodb后&#xff0c;会自动生成下面两个目录(mongod.conf中设定的)&#xff0c;用来存放日志和数据 /var/lib/mongo (数据目录) /var/log/mongodb (日志目录) 要启动一个单机版的mongodb&#xff0c;一般有两种方式&#xff1a; 第一种启动方式&#xff1a;直接使用…

Kotlin Executors线程池newSingleThreadExecutor单线程

Kotlin Executors线程池newSingleThreadExecutor单线程 import java.util.concurrent.Executorsfun main() {val mExecutorService Executors.newSingleThreadExecutor()for (i in 1..5) {mExecutorService.execute {println("seq-$i tid:${Thread.currentThread().threa…